У меня есть макетная плата Waveshare Open407V-D , по сути «материнская плата», в которой установлен комплект STM32F4DISCOVERY (этот комплект, для тех, кто с ним не знаком, сделан самой ST и основан на микроконтроллере STM32F407VG Cortex-M4) . Плата Open407V-D предоставляет очень мало функциональных возможностей, состоящая в основном из ряда разъемов, в которые подключаются модули (также продаваемые Waveshare). Один из этих модулей, называемый « NandFlash Board », содержит микросхему Samsung K9F1G08U0D 1 Gbit NAND Flash. Разъем на материнской плате подключает его к соответствующим сигналам FSMC:
Я пытаюсь подключиться к этому модулю. Я начал писать свой собственный код инициализации, а затем использовал идеи из этой ветки форума. Для кода чтения/записи/стирания я объединил некоторый пример кода для платы STM32F10E-EVAL, в комплекте со стандартной периферийной библиотекой STM32F1xx, поставляемой ST (особенно файл Utilities/STM32_EVAL/STM3210E_EVAL/stm3210e_eval_fsmc_nand.c), с примером кода для платы WaveShare NandFlash, которую можно скачать отсюда .
Я написал код, который заполняет страницу (2048 байт) памяти следующим массивом в форме с прямым порядком байтов (обратите внимание, что это массив 32-битных переменных):
uint32_t array[] = { 0, 1, 2, 3, 4, 5, ..., 509, 510, 511 };
Следовательно, при обратном чтении страницы можно было бы ожидать следующего:
00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00 ...
Однако на самом деле я обычно получаю что-то близкое к этому (отрывок из начала страницы):
00 00 00 00 01 00 00 00 02 00 00 00 03 00 00 00
04 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00
08 00 00 00 09 00 00 00 0A 00 00 00 0B 00 00 00
0C 00 00 00 0D 00 00 00 0E 00 00 00 0F 00 00 00
10 00 00 00 11 00 00 00 12 00 00 00 13 00 00 00
14 00 00 00 15 00 00 00 16 00 00 00 17 00 00 00
18 00 00 00 19 00 00 00 1A 00 00 00 1B 00 00 00
1C 00 00 00 1D 00 00 00 1E 00 00 00 1F 00 00 00
20 00 00 00 21 00 00 00 22 00 00 00 23 00 00 00
24 00 00 00 25 00 00 00 26 00 00 00 27 00 00 00
28 00 00 00 29 00 00 00 2A 00 00 00 2B 00 00 00
2C 00 00 00 2D 00 00 00 2E 00 00 00 2F 00 00 00
30 00 00 00 31 00 00 00 32 00 00 00 33 00 00 00
34 00 00 00 35 00 00 00 36 00 00 00 37 00 00 00
38 00 00 00 39 00 00 00 3A 00 00 00 3B 00 00 3C
00 00 00 3D 00 00 00 3E 00 00 00 3F 00 00 40 00
00 00 41 00 00 00 42 00 00 00 43 00 00 00 44 00
00 00 45 00 00 00 46 00 00 00 47 00 00 00 48 00
00 00 49 00 00 00 4A 00 00 00 4B 00 00 00 4C 00
00 00 4D 00 00 00 4E 00 00 00 4F 00 00 00 50 00
00 00 51 00 00 00 52 00 00 00 53 00 00 00 54 00
00 00 55 00 00 00 56 00 00 00 57 00 00 00 58 00
Как видно, иногда удаляется нулевой байт, а иногда в поток вставляется один (хотя случая вставки в данном конкретном примере не произошло). Посмотрите например на 3С и 40 байт в примере. Я также видел ситуации, в которых один из байтов повторяется, например, вместо того, чтобы 32 00 00 00 33 00 ...
получить32 00 00 33 33 00 ...
На самом деле, чтобы получить приведенные выше результаты, я не могу использовать рассчитанные тайминги setup/hold/wait/Hi-Z/tAR/tCLR (см. фрагменты кода ниже); Я не вычислил точный порог, но, по крайней мере, использование значения 100 тактовых циклов для настройки/удержания/ожидания/Hi-Z и 16 циклов для tAR/tCLR действительно работает. Результаты кажутся очень похожими (и довольно часто абсолютно одинаковыми) при каждом прогоне. Я пытался изменить адрес страницы, но я продолжаю получать те же результаты.
Одна вещь, которую я пробовал, — стирать и записывать шаблон только один раз, а затем считывать данные в цикле и проверять их с помощью отладчика. В большинстве случаев я всегда получаю один и тот же результат, хотя пару раз я получил немного разные результаты (например, случай повторения, 33
описанный выше). Таким образом, похоже, что есть ошибка в функции чтения, но я не могу исключить ошибку и в функции записи.
Для справки, я предоставляю большую часть своего кода, если это имеет значение. Во-первых, куча #define
s, которые могут понадобиться для ссылки в остальной части кода:
#define FSMC_Bank_NAND FSMC_Bank2_NAND
#define Bank_NAND_ADDR Bank2_NAND_ADDR
#define Bank2_NAND_ADDR ((uint32_t)0x70000000)
#define ROW_ADDRESS (Address.Page + (Address.Block + (Address.Zone * NAND_ZONE_SIZE)) * NAND_BLOCK_SIZE)
#define CMD_AREA (uint32_t)(1<<17) /* A17 = CLE high */
#define ADDR_AREA (uint32_t)(1<<16) /* A16 = ALE high */
#define DATA_AREA ((uint32_t)0x00000000)
#define NAND_CMD_AREA_A ((uint8_t)0x00)
#define NAND_CMD_AREA_B ((uint8_t)0x01)
#define NAND_CMD_AREA_C ((uint8_t)0x50)
#define NAND_CMD_READ_1 ((uint8_t)0x00)
#define NAND_CMD_READ_TRUE ((uint8_t)0x30)
#define NAND_CMD_WRITE0 ((uint8_t)0x80)
#define NAND_CMD_WRITE_TRUE1 ((uint8_t)0x10)
#define NAND_CMD_ERASE0 ((uint8_t)0x60)
#define NAND_CMD_ERASE1 ((uint8_t)0xD0)
#define NAND_CMD_READID ((uint8_t)0x90)
#define NAND_CMD_STATUS ((uint8_t)0x70)
#define NAND_CMD_LOCK_STATUS ((uint8_t)0x7A)
#define NAND_CMD_RESET ((uint8_t)0xFF)
#define NAND_VALID_ADDRESS ((uint32_t)0x00000100)
#define NAND_INVALID_ADDRESS ((uint32_t)0x00000200)
#define NAND_TIMEOUT_ERROR ((uint32_t)0x00000400)
#define NAND_BUSY ((uint32_t)0x00000000)
#define NAND_ERROR ((uint32_t)0x00000001)
#define NAND_READY ((uint32_t)0x00000040)
#define NAND_PAGE_SIZE ((uint16_t)0x0800) /* 2 * 1024 bytes per page w/o Spare Area */
#define NAND_BLOCK_SIZE ((uint16_t)0x0040) /* 64 pages per block */
#define NAND_ZONE_SIZE ((uint16_t)0x0400) /* 1024 Block per zone */
#define NAND_SPARE_AREA_SIZE ((uint16_t)0x0040) /* last 64 bytes as spare area */
#define NAND_MAX_ZONE ((uint16_t)0x0001) /* 1 zones of 1024 block */
#define ADDR_1st_CYCLE(ADDR) (uint8_t)((ADDR)& 0xFF) /* 1st addressing cycle */
#define ADDR_2nd_CYCLE(ADDR) (uint8_t)(((ADDR)& 0xFF00) >> 8) /* 2nd addressing cycle */
#define ADDR_3rd_CYCLE(ADDR) (uint8_t)(((ADDR)& 0xFF0000) >> 16) /* 3rd addressing cycle */
#define ADDR_4th_CYCLE(ADDR) (uint8_t)(((ADDR)& 0xFF000000) >> 24) /* 4th addressing cycle */
Это код инициализации:
void NAND_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
FSMC_NANDInitTypeDef FSMC_NANDInitStructure;
FSMC_NAND_PCCARDTimingInitTypeDef p;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD | RCC_AHB1Periph_GPIOE, ENABLE);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOD, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource11, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_FSMC);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_FSMC);
GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_FSMC);
RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC, ENABLE);
FSMC_NANDInitStructure.FSMC_AttributeSpaceTimingStruct = &p;
FSMC_NANDInitStructure.FSMC_CommonSpaceTimingStruct = &p;
FSMC_NANDStructInit(&FSMC_NANDInitStructure);
p.FSMC_SetupTime = 0;
p.FSMC_WaitSetupTime = 2;
p.FSMC_HoldSetupTime = 1;
p.FSMC_HiZSetupTime = 4;
FSMC_NANDInitStructure.FSMC_Bank = FSMC_Bank2_NAND;
FSMC_NANDInitStructure.FSMC_Waitfeature = FSMC_Waitfeature_Enable;
FSMC_NANDInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b;
FSMC_NANDInitStructure.FSMC_ECC = FSMC_ECC_Disable;
FSMC_NANDInitStructure.FSMC_TCLRSetupTime = 0;
FSMC_NANDInitStructure.FSMC_TARSetupTime = 0;
FSMC_NANDInit(&FSMC_NANDInitStructure);
FSMC_NANDCmd(FSMC_Bank2_NAND, ENABLE);
}
Это код для стирания страницы:
uint32_t NAND_EraseBlock(NAND_ADDRESS Address)
{
*(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_ERASE0;
*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_1st_CYCLE(ROW_ADDRESS);
*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_2nd_CYCLE(ROW_ADDRESS);
*(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_ERASE1;
return (NAND_GetStatus());
}
Код для написания одной или нескольких страниц (пока я пишу только одну страницу за раз):
uint32_t NAND_WriteSmallPage(uint8_t *pBuffer, NAND_ADDRESS Address, uint32_t NumPageToWrite)
{
uint32_t index = 0x00, numpagewritten = 0x00, addressstatus = NAND_VALID_ADDRESS;
uint32_t status = NAND_READY, size = 0x00;
while((NumPageToWrite != 0x00) && (addressstatus == NAND_VALID_ADDRESS) && (status == NAND_READY))
{
/*!< Page write command and address */
*(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_WRITE0;
*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = 0x00;
*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = 0x00;
*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_1st_CYCLE(ROW_ADDRESS);
*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_2nd_CYCLE(ROW_ADDRESS);
/*!< Calculate the size */
size = NAND_PAGE_SIZE + (NAND_PAGE_SIZE * numpagewritten);
/*!< Write data */
for(; index < size; index++)
{
*(__IO uint8_t *)(Bank_NAND_ADDR | DATA_AREA) = pBuffer[index];
}
*(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_WRITE_TRUE1;
/*!< Check status for successful operation */
status = NAND_GetStatus();
if(status == NAND_READY)
{
numpagewritten++;
NumPageToWrite--;
/*!< Calculate Next small page Address */
addressstatus = NAND_AddressIncrement(&Address);
}
}
return (status | addressstatus);
}
Код для чтения одной или нескольких страниц (опять же, сейчас я просто читаю одну страницу за раз):
uint32_t NAND_ReadSmallPage(uint8_t *pBuffer, NAND_ADDRESS Address, uint32_t NumPageToRead)
{
uint32_t index = 0x00, numpageread = 0x00, addressstatus = NAND_VALID_ADDRESS;
uint32_t status = NAND_READY, size = 0x00;
while((NumPageToRead != 0x0) && (addressstatus == NAND_VALID_ADDRESS))
{
/*!< Page Read command and page address */
*(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_READ_1;
*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = 0x00;
*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = 0x00;
*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_1st_CYCLE(ROW_ADDRESS);
*(__IO uint8_t *)(Bank_NAND_ADDR | ADDR_AREA) = ADDR_2nd_CYCLE(ROW_ADDRESS);
*(__IO uint8_t *)(Bank_NAND_ADDR | CMD_AREA) = NAND_CMD_READ_TRUE;
/*!< Calculate the size */
size = NAND_PAGE_SIZE + (NAND_PAGE_SIZE * numpageread);
/*!< Get Data into Buffer */
for(; index < size; index++)
{
pBuffer[index]= *(__IO uint8_t *)(Bank_NAND_ADDR | DATA_AREA);
}
numpageread++;
NumPageToRead--;
/*!< Calculate page address */
addressstatus = NAND_AddressIncrement(&Address);
}
status = NAND_GetStatus();
return (status | addressstatus);
}
Посмотрите на таблицу, которую вы хотите написать. Вы определили как unsigned long
values uint32_t array[] = { 0, 1, 2, 3, 4, 5, ..., 509, 510, 511 };
Так что - операция записи в порядке. тип unsigned long имеет длину 4 байта.
НержавеющаяСтальКрыса