Jump to content

    
Sign in to follow this  
moon333

Не могу подружить SPI FLASH и STM32

Recommended Posts

Пытаюсь подружит stm32f427 и SPI flash W25Q64FV.

 

Для начала научился читать из FLASH Device Identification по команде Read JEDEC ID (9Fh)

 

SPI4_CS_LOW;
while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI4, 0x9F);

while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);
data_spi = SPI_I2S_ReceiveData(SPI4);  // заглушка, чтобы очистить RXNE

while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI4, 0x00);

while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);
data_flash[0] = SPI_I2S_ReceiveData(SPI4);

while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI4, 0x00);

while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);
data_flash[1] = SPI_I2S_ReceiveData(SPI4);

while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_TXE) == RESET);
SPI_I2S_SendData(SPI4, 0x00);

	while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);
data_flash[2] = SPI_I2S_ReceiveData(SPI4);

SPI4_CS_HIGH;

 

Получаю вполне корректный ответ: 0xEF 0x40 0x17. Судя по даташиту такие значения имеют место быть.

 

824e917ced6a.png

 

Далее я пытался прочитать регистр состояния, после того как выполню команду Write Enable 0x06. По идее бит WEL должен быть установлен, однако читается одни нули 0x00.

 

Далее прилагаю код:

 

Инициализация SPI

void init_SPI()
{
	uint8_t x = 0x00;

//настройка CS и включения питания
GPIO_InitTypeDef GPIO_CS;	
GPIO_InitTypeDef GPIO_POW;

GPIO_CS.GPIO_Pin = GPIO_Pin_11;
GPIO_CS.GPIO_Mode = GPIO_Mode_OUT;
GPIO_CS.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_CS.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_CS.GPIO_OType = GPIO_OType_PP;

GPIO_POW.GPIO_Pin = GPIO_Pin_11;
GPIO_POW.GPIO_Mode = GPIO_Mode_OUT;
GPIO_POW.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_POW.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_POW.GPIO_OType = GPIO_OType_PP;

GPIO_Init(GPIOE, &GPIO_CS);
GPIO_Init(GPIOB, &GPIO_POW);


SPI_InitTypeDef SPI_struct_itit; //объявляем структуру для инициализации SPI
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI4, ENABLE); // включаем тактирование SPI4

	/* Инициализация структуры
	 Initialize the SPI_Direction - Двухнаправленный SPI или Однонаправленный
	 Initialize the SPI_Mode member  - Slave (ведомый) или Master(Мастер) 
	 Initialize the SPI_DataSize member - бит в сообщении (8 или 16)
	 Initialize the SPI_CPOL member - задаёт режим работы (режим 0,1,2,3)
	 Initialize the SPI_CPHA member - задаёт режим работы (режим 0,1,2,3)
	 Initialize the SPI_NSS member - Управление CS HARD - автоматически, soft - программно
	 Initialize the SPI_BaudRatePrescaler member - делитель для тактовой частоты SPI
	 Initialize the SPI_FirstBit member - младший или старшый байт первый 
	 Initialize the SPI_CRCPolynomial member - CRC полином
	*/
 SPI_struct_itit.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
 SPI_struct_itit.SPI_Mode = SPI_Mode_Master;
 SPI_struct_itit.SPI_DataSize = SPI_DataSize_8b;
 SPI_struct_itit.SPI_CPOL = SPI_CPOL_Low;
 SPI_struct_itit.SPI_CPHA = SPI_CPHA_1Edge;	
 SPI_struct_itit.SPI_NSS = SPI_NSS_Soft;
 SPI_struct_itit.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
 SPI_struct_itit.SPI_FirstBit = SPI_FirstBit_MSB;
 SPI_struct_itit.SPI_CRCPolynomial = 7;

SPI_Init (SPI4,&SPI_struct_itit);	// инициализируем SPI4
SPI_Cmd(SPI4,ENABLE);
}

 

Инициализация GPIO SPI

    // инициализация SPI4: SCL,MOSI
    Other_GPIO.GPIO_Pin =   GPIO_Pin_12 | GPIO_Pin_14;
    Other_GPIO.GPIO_Mode = GPIO_Mode_AF;
    Other_GPIO.GPIO_OType = GPIO_OType_PP;
    Other_GPIO.GPIO_PuPd = GPIO_PuPd_NOPULL;
    Other_GPIO.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOE, &Other_GPIO);
    // инициализация SPI4: MISO
    Other_GPIO.GPIO_Pin =  GPIO_Pin_13;
    Other_GPIO.GPIO_Mode = GPIO_Mode_AF;
    Other_GPIO.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOE, &Other_GPIO);
    // инициализация SPI4: NSS
    Other_GPIO.GPIO_Pin =  GPIO_Pin_11;
    Other_GPIO.GPIO_Mode = GPIO_Mode_OUT;
    Other_GPIO.GPIO_OType = GPIO_OType_PP;
    Other_GPIO.GPIO_PuPd = GPIO_PuPd_NOPULL;
    Other_GPIO.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOE, &Other_GPIO);
    //Выбираем альтернативную функцию для всех PIN-SPI
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_SPI4);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_SPI4);
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_SPI4);

 

Посылка команды Write Enable

//включение записи во flash
void FLASH_Write_Enable(SPI_TypeDef* SPIx)
{
    if (SPIx == SPI4)    SPI4_CS_LOW;
    else                __NOP; // Временная заглушка для SPI1
    
    while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPIx, WriteEnable);
    
    if (SPIx == SPI4)    SPI4_CS_HIGH;
    else                __NOP; // Временная заглушка для SPI1
    
}

 

Ну и функция считывания Статус регистра

uint8_t READ_Stat_Reg (SPI_TypeDef* SPIx)
{
    volatile uint8_t byte = 0x00;
    
    SPI4_CS_LOW;
        
    while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI4, 0x05);
    
    while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);
    byte = SPI_I2S_ReceiveData(SPI4);
    
    while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);
    SPI_I2S_SendData(SPI4, 0x00);
    
    while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);
    byte = SPI_I2S_ReceiveData(SPIx);
    
    SPI4_CS_HIGH;
    
    return byte;
    
}

 

основная main()

int main(void)
{

init_CLOCK();

init_GPIO();

GPIOB->ODR &= ~GPIO_Pin_11; //power FLASH on

init_SPI();

FLASH_Write_Enable(SPI4);

x = READ_Stat_Reg(SPI4);

..................

 

 

брейкпоинт ставлю в функции READ_Stat_Reg на строчке SPI4_CS_HIGH;

 

 

Почему читаются одни 0. Наверняка, что то очевидное... Не вижу :(

Edited by moon333

Share this post


Link to post
Share on other sites
Что на шине творится во время передачи смотрели осциллографом или лог.анализатором?

 

Смотрел осциллографом:

Данные бегут. Клок есть. CS тоже дёргается.

 

Странно что ID нормально считывается.

Share this post


Link to post
Share on other sites

Мне кажется что проблема с флагами ожидания пересылки байт. Возможно, где-то Вы не дожидаетесь отправки байта и сразу начинаете следующие операции. Посмотрите в мануале как работать с регистрами и флагами блока SPI, а потом найдите несоответствие с Вашим кодом.

Share this post


Link to post
Share on other sites
Мне кажется что проблема с флагами ожидания пересылки байт. Возможно, где-то Вы не дожидаетесь отправки байта и сразу начинаете следующие операции. Посмотрите в мануале как работать с регистрами и флагами блока SPI, а потом найдите несоответствие с Вашим кодом.

 

Перед тем как что то писать в регистр SPI4->DR стоит:

while(SPI_I2S_GetFlagStatus(SPIx, SPI_I2S_FLAG_TXE) == RESET);

 

Я посмотрел, вроде везде так сделано.

Share this post


Link to post
Share on other sites
Я посмотрел, вроде везде так сделано.

 

Что значит "везде"? Сверьтесь с мануалом и, если там все точно так же, то можно уже более детально смотреть.

Share this post


Link to post
Share on other sites
Что значит "везде"? Сверьтесь с мануалом и, если там все точно так же, то можно уже более детально смотреть.

 

У Вас подозрение на то, что я пытаюсь отправить данные когда ещё SPI не готов.

Правильно ли я Вас понимаю?

Share this post


Link to post
Share on other sites

Везде после

 

while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_TXE) == RESET);

SPI_I2S_SendData(SPI4, ...);

 

добавьте

 

while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);

... SPI_I2S_ReceiveData(SPI4);

 

Если не понятно зачем - прочитайте про работу SPI в RM

 

Share this post


Link to post
Share on other sites
добавьте

while(SPI_I2S_GetFlagStatus(SPI4, SPI_I2S_FLAG_RXNE) == RESET);

... SPI_I2S_ReceiveData(SPI4);

 

Если не понятно зачем - прочитайте про работу SPI в RM

 

Overrun flag к моменту приёма всегда был чист. Хотя изначально я тоже на это напарывался.

 

Всего лишь подозрение, код смотрел по-диагонали. Посмотрите (помимо обязательного чтения мануала) также эту статью

 

Спасибо. До этого читал по диагонали и из за этого допустил ошибку. Снимал CS раньше, чем успевал передать все данные...

 

Добавил:

while (SPI_I2S_GetFlagStatus(SPIx,SPI_FLAG_BSY)!=RESET);

Всё заработало.

Edited by moon333

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this