由于项目需要开始接触Microchip(原Atmel)家的这款MCU,使用工具是SAM E70 X PLAINED ULTRA开发板。本系列用于记录从0开始一步步熟悉这款MCU的开发过程。开发板外设资源丰富,之前一直是使用HAL库开发ST/GD系列的MCU,Microchip的开发风格与前两者存在一定差异,借此机会巩固一下基础知识。
- ATSAME70Q21B Microcontroller
- Cortex-M7 Core-based Microcontroller
- Max Speed: 300MHz
- Flash: 2048KB

EFC(Enhanced Flash Controller)
Microchip推出的嵌入式系统闪存控制器,用于管理Flash存储器的读写操作。
关于内部Flash有以下大小定义:
#define EFC_SECTORSIZE 8192//扇区大小,8k
#define EFC_PAGESIZE 512//页大小,512B
#define EFC_LOCKSIZE 0x4000//可锁定大小,16k
在plib_efc.h中有几个常用的函数声明:
bool EFC_Read( uint32_t *data, uint32_t length, uint32_t address );//从Flash地址读取数据
bool EFC_SectorErase( uint32_t address );//扇区擦除
bool EFC_PageWrite( uint32_t *data, uint32_t address );//按页为单位写
bool EFC_QuadWordWrite( uint32_t *data, uint32_t address );//以4字为单位写(16bytes)
关于擦除存在一点疑问,查看数据手册中,有三种不同类型的擦除cmd,如下图:

查看EFC_SectorErase函数的实现却是使用的EPA命令:
bool EFC_SectorErase( uint32_t address )
{
uint16_t page_number;
if (DATA_CACHE_IS_ENABLED() != 0U)
{
DCACHE_INVALIDATE_BY_ADDR((uint32_t*)address, (int32_t)EFC_SECTORSIZE);
}
/*Calculate the Page number to be passed for FARG register*/
page_number = (uint16_t)((address - IFLASH_ADDR) / IFLASH_PAGE_SIZE);
/* Issue the FLASH erase operation*/
EFC_REGS->EEFC_FCR = (EEFC_FCR_FCMD_EPA|EEFC_FCR_FARG((uint32_t)page_number|0x2U)|EEFC_FCR_FKEY_PASSWD);
efc_status = 0;
return true;
}
看起来是以页为单位进行的擦除,有点不解。
使用测试
Flash是只能从1写0,不能从0写1的硬件,在使用前需要擦除(全部恢复为0xff,全1)。
修改main函数,代码如下:
#define FLASH_TEST_ADDRESS 0x404000
uint8_t hello_str[] = "hello from the SAM E70 X PLAINED ultra";
uint8_t test_data[10] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
uint32_t efc_data[10];
uint32_t efc_wr_data[4] = {0x11223344, 0x55667788, 0x99aabbcc, 0xddeeff00};
uint32_t efc_rd_data[4];
uint8_t read_str[64];
int main ( void )
{
/* Initialize all modules */
SYS_Initialize ( NULL );
printf("%s at %s %s\r\n", hello_str, __DATE__, __TIME__);
EFC_SectorErase(FLASH_TEST_ADDRESS);//擦除
EFC_Read(efc_data, sizeof(efc_data), FLASH_TEST_ADDRESS);
for (int i = 0; i < 10; i++) {
printf("%lx ", efc_data[i]);//检查擦除后是否全为0xff
}
EFC_QuadWordWrite(efc_wr_data, FLASH_TEST_ADDRESS);//4字写
printf("\n");
EFC_Read(efc_rd_data, sizeof(efc_rd_data), FLASH_TEST_ADDRESS);
for (int i = 0; i < 4; i++) {
printf("%lx ", efc_rd_data[i]);
}
EFC_PageWrite((uint32_t *)hello_str, FLASH_TEST_ADDRESS + 0x100);//Page写
EFC_Read((uint32_t *)read_str, sizeof(read_str), FLASH_TEST_ADDRESS);
printf("\nread from flash: %s\n", read_str);
while ( true )
{
LED2_Toggle();
SYSTICK_DelayMs(500);
}
/* Execution should not come here during normal operation */
return ( EXIT_FAILURE );
}
测试输出:
hello from the SAM E70 X PLAINED ultra at Nov 11 2025 15:48:39
ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff ffffffff
11223344 55667788 99aabbcc ddeeff00
read from flash: hello from the SAM E70 X PLAINED ultra
EEPROM
开发板板载了一颗256 bytes的EEPROM,型号为AT24MAC402,通过IIC与MCU通信。

根据原理图及数据手册得知设备地址为0x57,使用IIC向内存地址写入数据,代码如下:
int main ( void )
{
/* Initialize all modules */
SYS_Initialize ( NULL );
printf("%s at %s %s\r\n", hello_str, __DATE__, __TIME__);
uint8_t buf[6] = {0x00, 0x11, 0x22, 0x33, 0x44, 0x55};//向0地址写入5个字节数据
TWIHS0_Write(0x57, buf, 6);
while (TWIHS0_IsBusy());
delay_ms(5);
uint8_t reg_addr = 0x00;
uint8_t value[5];
TWIHS0_WriteRead(0x57, ®_addr, 1, value, 5);
while (TWIHS0_IsBusy());
printf("read from eeprom: %x, %x, %x, %x, %x\n", value[0], value[1], value[2], value[3], value[4]);
while ( true )
{
LED2_Toggle();
SYSTICK_DelayMs(500);
/* Maintain state machines of all polled MPLAB Harmony modules. */
// SYS_Tasks ( );
}
/* Execution should not come here during normal operation */
return ( EXIT_FAILURE );
}
读出数据与写入一致。
hello from the SAM E70 X PLAINED ultra at Nov 11 2025 16:48:26
read from eeprom: 11, 22, 33, 44, 55

写入过程:

读出过程:

修改代码,注释掉写入部分,上电后直接读:

QSPI Flash
未测试,基于生成的代码无法完成,需要自行封装读写函数,工作量较大。
开发板板载一颗4-MB QSPI Flash,型号为SST26VF032BA,通过QSPI与MCU通信(也可以选择使用标准SPI)。
QSPI共有6根线,片选CS、时钟SCK以及4根数据线。
SAM E70内封Flash已是大容量了,在平时开发中,会有其他厂家MCU本身不带Flash而是采用外置Flash,常用的就是QSPI Flash。
SDHC
未测试
728

被折叠的 条评论
为什么被折叠?



