Перейти к содержанию
    

STM32F4: SPI2 через DMA

Добрый день.

Вроде не первый раз пишу для STM и вроде по букварю, но нарвался. Есть STM32F405. К нему через SPI2 присоединена флеша на spi.

Читаю из порта данные флеши вручную - корректно. Как только читаю по DMA - в приемном буфере нули.

Код инициализации порта:

 

   // 1. Clock setup: spi port and pins
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

   // 2. Pins setup
   GPIO_InitTypeDef GPIO_InitStructure;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;

   // SCK
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
   GPIO_Init(GPIOB, &GPIO_InitStructure);
   // MISO
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
   GPIO_Init(GPIOC, &GPIO_InitStructure);
   // MOSI
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
   GPIO_Init(GPIOC, &GPIO_InitStructure);

   GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_SPI2);    // SCK
   GPIO_PinAFConfig(GPIOC, GPIO_PinSource2, GPIO_AF_SPI2);     // MISO
   GPIO_PinAFConfig(GPIOC, GPIO_PinSource3, GPIO_AF_SPI2);     // MOSI

   // NSS
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
   GPIO_Init(GPIOB, &GPIO_InitStructure);
   GPIO_SetBits(GPIOB, GPIO_Pin_12);


   // 3. SPI setup
   setFlashNssHigh();

   SPI_InitTypeDef SPI_InitStructure;
   SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
   SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
   SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
   SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;     // SPI_CPOL_Low
   SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;    //SPI_CPHA_1Edge
   SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
   SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16; // SPI_BaudRatePrescaler_2 SPI_BaudRatePrescaler_4;//
   SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
   SPI_InitStructure.SPI_CRCPolynomial = 7;
   SPI_Init(SPI2, &SPI_InitStructure);
   while(SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); 
   SPI_Cmd(SPI2, ENABLE);

 

Читаю данные:

    setTerminalMessage(info, "Reading data");
   setFlashNssLow();
   spiByteExchange(READ_DATA); // command
   spiByteExchange(0x00);      // address
   spiByteExchange(0x00);      // address
   spiByteExchange(0x00);      // address
   for(i = 0; i < 20; i++){
       rcvByte = spiByteExchange(0x00);
       setTerminalMessage(info, "Data[%02d] - %02x", i, rcvByte);
   }
   setFlashNssHigh();

 

Получаю FF на выходе, что корректно. Также корректно читается ID flash памяти.

Пытаюсь инициализировать DMA

 

   DMA_Cmd(DMA1_Stream3, DISABLE);
   DMA_Cmd(DMA1_Stream4, DISABLE);

   SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, DISABLE);
   SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, DISABLE);
   SPI_Cmd(SPI2, DISABLE);

   DMA_DeInit(DMA1_Stream4);
   while (DMA_GetCmdStatus(DMA1_Stream4) != DISABLE);

   DMA_DeInit(DMA1_Stream3);
   while (DMA_GetCmdStatus(DMA1_Stream3) != DISABLE);


   memset((void *)gl_rcvFlashBuffer, 0, DMA_BUFF_SZ);
   memset((void *)gl_trnFlashBuffer, 0, DMA_BUFF_SZ);
   gl_trnFlashBuffer[0] = READ_DATA; // PAGE_PROGRAM;

   // 1. DMA Clock
   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);

   // 2. Interrupt
   NVIC_InitTypeDef NVIC_InitStructure;
   NVIC_InitStructure.NVIC_IRQChannel = DMA1_Stream3_IRQn; // Only rx interrupt
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);

   // 2. DMA Structure
   // DMA_InitTypeDef DMA_InitStructure;
   // 2.2. Common
   DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
   DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
   DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
   DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
   DMA_InitStructure.DMA_Priority = DMA_Priority_High;
   DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
   DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
   DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
   DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
   DMA_InitStructure.DMA_Channel = DMA_Channel_0;
   DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(SPI2->DR));
   // 2.3. TX DMA
   DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)gl_trnFlashBuffer;
   DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
   DMA_InitStructure.DMA_BufferSize = DMA_BUFF_SZ;
   DMA_Init(DMA1_Stream4, &DMA_InitStructure);

   // 2.3. RX DMA
   DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)gl_rcvFlashBuffer;
   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
   DMA_InitStructure.DMA_BufferSize = DMA_BUFF_SZ;
   DMA_Init(DMA1_Stream3, &DMA_InitStructure);

   // 2.4. Enabling only rx interrupt
   DMA_ITConfig(DMA1_Stream3, DMA_IT_TC , ENABLE);

   DMA_ClearFlag(DMA1_Stream3, DMA_FLAG_TCIF3);
   DMA_ClearFlag(DMA1_Stream4, DMA_FLAG_TCIF4);

   DMA_Cmd(DMA1_Stream3, ENABLE); // Enable the DMA SPI RX Stream
   DMA_Cmd(DMA1_Stream4, ENABLE); // Enable the DMA SPI TX Stream

   SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
   SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);

   setTerminalMessage(info, "Starting");
   setFlashNssLow();
   gl_FlashDmaOn = true;
   SPI_Cmd(SPI2, ENABLE);

   while(true == gl_FlashDmaOn);
   setTerminalMessage(info, "Done");

   setTerminalMessage(info, "DMA read data");
   for(i = 0; i < 50; i++){
       setTerminalMessage(info, "Data[%02d] - %02x", i, gl_rcvFlashBuffer[i]);
   }

 

Код прерывания:

 
void DMA1_Stream3_IRQHandler(void)
{
   if(DMA_GetITStatus(DMA1_Stream3, DMA_IT_TCIF3)!= RESET){
        DMA_ClearITPendingBit(DMA1_Stream3, DMA_IT_TCIF3);
        // Clear NSS
        gl_FlashDmaOn = false;
        setFlashNssHigh();
    }
}

 

Буфера объявлены как

#define DMA_BUFF_SZ (256 + 4)

static uint8_t gl_trnFlashBuffer[DMA_BUFF_SZ];

static uint8_t gl_rcvFlashBuffer[DMA_BUFF_SZ];

volatile bool_t gl_FlashDmaOn = false;

 

По осциллогафу на chip select DMA отрабатывает корректно, в приемном буфере - нули.

Есть ли мысли? Может надо как-то выравнивать буфер? Или забыл что?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробуйте определить массивы для DMA, с атрибутом __attribute__((aligned(32)))

мой массив

uint8_t spi1_rx[ADS131_DATA_SIZE] __attribute__((aligned(32)));

Изменено пользователем rtfcnf

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробуйте определить массивы для DMA, с атрибутом __attribute__((aligned(32)))

мой массив

uint8_t spi1_rx[ADS131_DATA_SIZE] __attribute__((aligned(32)));

Без изменений, к сожалению.

Изменено пользователем zemlemer

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Без изменений, к сожалению.

 

1 ) Попробуйте DMA_PeripheralDataSize = DMA_PeripheralDataSize_Long. как пишут в даташите на STM,к регистрам периферии доступ по слову или по двойному слову

2) в DMA установить бит , отвечающий за flow control "dma".CR.PFCTRL=1;(по идее нужно устанавливать,но не факт)

ну само собой буфер данных выровнен по 4 байтной границе

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть ли мысли? Может надо как-то выравнивать буфер? Или забыл что?

Для побайтового доступа надо установить MBURST в 16 (не знаю, чему это соответствует в терминах StdPeriphLib).

Вот топик, где я с этим разбирался: ссылка (читать до конца, там есть тонкие моменты с выравниванием).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для побайтового доступа надо установить MBURST в 16 (не знаю, чему это соответствует в терминах StdPeriphLib).

Вот топик, где я с этим разбирался: ссылка (читать до конца, там есть тонкие моменты с выравниванием).

Оказалось все гораздо проще. Если выставить chip select до старта spi, то ловится лишний клок.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Оказалось все гораздо проще. Если выставить chip select до старта spi, то ловится лишний клок.

 

Так может у SPI неправильно настроена полярность клока?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У Вас

. . .
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
. . .

Попробуйте оставить только один канал DMA для проверки - который работает с флеш.

 

Если не секрет, что за флеш используется ?

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И от этого все FF-ы превращаются в нули? :)

От лишнего клока вначале? Естественно. Вместо команды на чтение идет неизвестно что.

 

У Вас

. . .
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Rx, ENABLE);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
. . .

Попробуйте оставить только один канал DMA для проверки - который работает с флеш.

 

Если не секрет, что за флеш используется ?

 

M25P80.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...