⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 atmel-flash.c

📁 MANTIS是由科罗拉多大学开发的传感器网络嵌入式操作系统。 这是mantis的0.9.5版本的源码。
💻 C
📖 第 1 页 / 共 2 页
字号:
//  This file is part of MANTIS OS, Operating System//  See http://mantis.cs.colorado.edu/////  Copyright (C) 2003,2004,2005 University of Colorado, Boulder////  This program is free software; you can redistribute it and/or//  modify it under the terms of the mos license (see file LICENSE)/** @file atmel-flash.c * @brief External 500k flash memory */#include "mos.h"#ifdef ARCH_AVR#include <avr/io.h>#include <avr/interrupt.h>#include <avr/signal.h>#include "clock.h"#include "mutex.h"#include "atmel-flash.h"#include "dev.h"#include "printf.h"mos_mutex_t atmel_flash_mutex;static uint32_t atmel_flash_addr;static uint8_t cur_buff;static uint16_t cur_page;static uint8_t dirty;			// This will never be set in unbuffered modestatic uint8_t flash_mode;static void atmel_flash_low();static void atmel_flash_high();static uint8_t atmel_flash_send_byte(uint8_t spiOut);static uint8_t atmel_flash_get_byte();static void atmel_flash_read_memory(uint16_t page,				     uint16_t offset, 				     void *reqData, uint16_t len);static uint16_t atmel_flash_crc_memory(uint16_t page,					uint16_t offset, 					uint32_t len);static uint8_t atmel_flash_busy();static uint8_t atmel_flash_write_buffer(uint8_t selected, uint16_t offset, 					 void *reqdata, uint16_t len);static uint8_t atmel_flash_flush_buffer(uint8_t selected, uint16_t page);static uint8_t atmel_flash_compare_buffer(uint8_t selected, uint16_t page);static uint8_t atmel_flash_fill_buffer(uint8_t selected, uint16_t page);static uint8_t atmel_flash_erase_page(uint16_t page);uint8_t dev_mode_DEV_ATMEL_FLASH (uint8_t mode){   uint8_t retcode = DEV_OK;      if (flash_mode == mode)      return retcode;      flash_mode = mode;      switch(mode)   {   case ATMEL_FLASH_MODE_UNBUFFERED:      if (dirty) {	 while (atmel_flash_busy ())	    ;	 atmel_flash_flush_buffer(cur_buff, cur_page);	 dirty = 0;	 while (atmel_flash_busy ())	    ;      }      break;   case ATMEL_FLASH_MODE_BUFFERED:      cur_buff = ATMEL_FLASH_BUFFER_1;      // The first comparison in write will always fail      cur_page = ATMEL_FLASH_MAX_PAGES;       dirty = 0;      break;   default:      retcode = DEV_BAD_MODE;      break;   }      return retcode;}uint8_t dev_ioctl_DEV_ATMEL_FLASH (int8_t request, ...){   uint32_t arg;   va_list ap;      va_start (ap, request);      switch (request) {   case DEV_SEEK:      arg = va_arg (ap, uint32_t);      atmel_flash_addr = arg;      break;   case DEV_FLUSH:      if (dirty) {	 while (atmel_flash_busy ())	    ;	 atmel_flash_flush_buffer(cur_buff, cur_page);	 dirty = 0;	 while (atmel_flash_busy ())	    ;      }      break;   case DEV_LOCK:      break;   case DEV_UNLOCK:      break;   default:      return DEV_BAD_IOCTL;         }      va_end (ap);      return DEV_OK;}/** @brief Read from the current flash address into p, for count bytes */uint16_t dev_read_DEV_ATMEL_FLASH (void *p, uint16_t count){   uint16_t page, offset;   uint8_t *buf = (uint8_t *)p;      page = atmel_flash_addr / ATMEL_FLASH_PAGE_SIZE;   offset = atmel_flash_addr % ATMEL_FLASH_PAGE_SIZE;      if (dirty && page <= cur_page &&        page + (offset + count) / ATMEL_FLASH_PAGE_SIZE >= cur_page) {      while (atmel_flash_busy ())	 ;      atmel_flash_flush_buffer(cur_buff, cur_page);      dirty = 0;   }   // Wait for any previous actions to complete   while (atmel_flash_busy ())      ;   atmel_flash_read_memory (page, offset, buf, count);      return count;}/** @brief Write p into the current flash address, for count bytes */uint16_t dev_write_DEV_ATMEL_FLASH (const void *p, uint16_t count){   uint16_t page, offset, num_bytes;   uint16_t index = 0;   uint8_t *buf = (uint8_t *)p;      page = atmel_flash_addr / ATMEL_FLASH_PAGE_SIZE;   offset = atmel_flash_addr % ATMEL_FLASH_PAGE_SIZE;      while (atmel_flash_busy ())      ;   while (count > 0)   {      if (count + offset > ATMEL_FLASH_PAGE_SIZE)	 num_bytes = ATMEL_FLASH_PAGE_SIZE - offset;      else	 num_bytes = count;            if (flash_mode == ATMEL_FLASH_MODE_BUFFERED)      {	 if (page != cur_page)	 {	    if (dirty) {	       while (atmel_flash_busy ())		  ;	       atmel_flash_flush_buffer(cur_buff, cur_page);	       dirty = 0;	    }	    cur_buff = (cur_buff==ATMEL_FLASH_BUFFER_1?			ATMEL_FLASH_BUFFER_2 : ATMEL_FLASH_BUFFER_1);	    cur_page = page;	    if (num_bytes < ATMEL_FLASH_PAGE_SIZE) {	       while (atmel_flash_busy ())		  ;	       atmel_flash_fill_buffer(cur_buff, page);	    }	    // Erase next page right now	    while (atmel_flash_busy ())	       ;	    atmel_flash_erase_page (page);	 }			 atmel_flash_write_buffer(cur_buff, offset, &buf[index], num_bytes);	 dirty = 1;      } else {	 atmel_flash_fill_buffer (ATMEL_FLASH_DEFAULT_BUFFER, page);	 while (atmel_flash_busy ())	    ;	 atmel_flash_erase_page (page);	 while (atmel_flash_busy ())	    ;	 atmel_flash_write_buffer (ATMEL_FLASH_DEFAULT_BUFFER,				   offset, &buf[index], num_bytes);	 atmel_flash_flush_buffer (ATMEL_FLASH_DEFAULT_BUFFER, page);	 while (atmel_flash_busy ())	    ;      }		      index += num_bytes;      atmel_flash_addr += num_bytes;      count -= num_bytes;		      page++;      offset = 0;   }   return count;}/* device-specific functions */void atmel_flash_init (void){   mos_mutex_init (&atmel_flash_mutex);   uint8_t handle = mos_disable_ints ();      // set the flash select pin   DDRA |= 1 << ATMEL_FLASH_SELECT_PIN;   // set the pin high   ATMEL_FLASH_SELECT |= 1 << ATMEL_FLASH_SELECT_PIN;   // clear flash clock   ATMEL_FLASH_PORT &= ~(1 << ATMEL_FLASH_CLK);   // set flash clock output direction   ATMEL_FLASH_DIRE |= 1 << ATMEL_FLASH_CLK;   // clear flash out pin   ATMEL_FLASH_PORT &= ~(1 << ATMEL_FLASH_OUT);   // set flash out pin direction   ATMEL_FLASH_DIRE &= ~(1 << ATMEL_FLASH_OUT);   // clear flash in pin   ATMEL_FLASH_PORT |= 1 << ATMEL_FLASH_IN;   // set flash in pin direction   ATMEL_FLASH_DIRE |= 1 << ATMEL_FLASH_IN;   mos_enable_ints (handle);      // Unbuffered mode is default for backward compatibility   flash_mode = ATMEL_FLASH_MODE_UNBUFFERED;   atmel_flash_addr = 0;   cur_buff = ATMEL_FLASH_BUFFER_1;   cur_page = ATMEL_FLASH_MAX_PAGES;   dirty = 0;      // must wait 20 ms before device is ready to use    mos_udelay (20000);}/** @brief Compare buf to the current flash address, for count bytes */uint8_t atmel_flash_compare (uint8_t *buf, uint16_t count){   uint16_t page, offset, num_bytes;   uint16_t index = 0;   uint8_t compare = 0;   if (dirty) {      while (atmel_flash_busy ())	 ;      atmel_flash_flush_buffer(cur_buff, cur_page);      dirty = 0;   }   // Wait for any previous actions to complete   while (atmel_flash_busy ())      ;   while (count > 0) {      page = atmel_flash_addr / ATMEL_FLASH_PAGE_SIZE;      offset = atmel_flash_addr % ATMEL_FLASH_PAGE_SIZE;      if (count + offset > ATMEL_FLASH_PAGE_SIZE)	 num_bytes = ATMEL_FLASH_PAGE_SIZE - offset;      else	 num_bytes = count;      // Are we not comparing a whole page?      if (num_bytes < ATMEL_FLASH_PAGE_SIZE) {	 atmel_flash_fill_buffer (ATMEL_FLASH_DEFAULT_BUFFER,				  page);	 while (atmel_flash_busy ())	    ;      }      // Write the data we want to compare to the buffer      atmel_flash_write_buffer (ATMEL_FLASH_DEFAULT_BUFFER,				offset, &buf[index], num_bytes);	      // Compare the buffer to main memory      if (atmel_flash_compare_buffer (ATMEL_FLASH_DEFAULT_BUFFER, page)) {	 compare = 1;	 break;      }      index += num_bytes;      atmel_flash_addr += num_bytes;      count -= num_bytes;   }   // In case we exited the loop early, act like we read the whole range   atmel_flash_addr += count;   return compare;}/** @brief Compute the crc from the current flash address, for count bytes */uint16_t atmel_flash_crc(uint32_t count){   uint16_t page, offset, crc;      page = atmel_flash_addr / ATMEL_FLASH_PAGE_SIZE;   offset = atmel_flash_addr % ATMEL_FLASH_PAGE_SIZE;   if (dirty && page <= cur_page &&        page+(offset+count)/ATMEL_FLASH_PAGE_SIZE >= cur_page)   {      while (atmel_flash_busy ())	 ;      atmel_flash_flush_buffer(cur_buff, cur_page);      dirty = 0;   }   // Wait for any previous actions to complete   while (atmel_flash_busy ())      ;   crc = atmel_flash_crc_memory (page, offset, count);      return crc;}/** @brief Set the flash in low */static inline void atmel_flash_low (void) {   uint8_t handle = mos_disable_ints ();      // clear flash clock   ATMEL_FLASH_PORT &= ~(1 << ATMEL_FLASH_CLK);   // clear select pin   ATMEL_FLASH_SELECT &= ~(1 << ATMEL_FLASH_SELECT_PIN);   mos_enable_ints (handle);}/** @brief Set the flash pin high */static inline void atmel_flash_high (void){   // set the pin high   ATMEL_FLASH_SELECT |= 1 << ATMEL_FLASH_SELECT_PIN;}// 0x11010111, 3 and 5 pin, pull low FLASH_IN and FLASH_CLK  /** @brief Init the bit macro. */#define BITINIT  uint8_t clrClkAndData = PORTD & ~0x28 // first of all, the data is shifted in in rising edge and out in falling// The I/O address for PORTD is 18, for PIND is 16// first set the clk to low and the input to low, then // check the #n bit in spiOut.  //  if 0,    then skip the step of writing the #n bit in FLASH_IN to high //           else pull the flash_in to high// then set  clk to rising edge// then check whether the FLASH_OUT in PIND is 0// if yes, then skip (i.e. set the spiIn's bit to 0) //         else set the spiIn's bit to 1/** @brief Write one bit of data. */#define WRITEBIT(n)					\   PORTD = clrClkAndData;				\   asm __volatile__					\   (  "sbrc %2," #n "\n"				\      "\tsbi 18,3\n"					\      "\tsbi 18,5\n"					\      : "=d" (spiIn) : "0" (spiIn), "r" (spiOut))/** @brief Read one bit of data. */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -