|
|
  |
stm32f411 spi1+DMA, непрерывная выдача данных |
|
|
|
Aug 31 2017, 12:24
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342

|
Привожу код что и как делаю, вопрос в том, что в прерывание ДМА входит, а вот уже в обработчике прерывания в if не входити ессно нет переключения между массивами, что не так?Надеюсь на конструктивный диалог, заранее спасибо. Код void DMA2_Stream5_IRQHandler ( void ) { uart2_putcharPoll ( 'I' );//, xNoBlock );
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
if ( DMA_GetITStatus ( SPI_DMA_MASTER_Tx_DMA_Stream, DMA_IT_TCIF5 ) == SET ) { uart2_putcharPoll ( 'F' );//, xNoBlock );
// Clear DMA Stream Transfer Complete interrupt pending bit
if ( CurrentBufSPI1 == buf1 ) { CurrentBufSPI1 = buf2; uart2_putcharPoll ( '2' );//, xNoBlock ); }
if ( CurrentBufSPI1 == buf2 ) { CurrentBufSPI1 = buf1; uart2_putcharPoll ( '1' );//, xNoBlock ); } DMA_Cmd ( SPI_DMA_MASTER_Tx_DMA_Stream, DISABLE ); DMA_ClearITPendingBit ( SPI_DMA_MASTER_Tx_DMA_Stream, DMA_IT_TCIF5 ); } xSemaphoreGiveFromISR ( xSemaphore_spi1, &xHigherPriorityTaskWoken ); xTaskResumeFromISR (&xHandleSPI1); uart2_putcharPoll ( 'E' );//, xNoBlock ); portEND_SWITCHING_ISR ( xHigherPriorityTaskWoken ); } Код void Task_SPI1 ( void *pvParameters ) { xSemaphoreTake ( xSemaphore_spi1, portMAX_DELAY );
for (;; ) { if ( CurrentBufSPI1 == buf1 ) { ukladkabufTXSPI1 ( Buffer1TX_SPI1 );
DMA_Config ( Buffer1TX_SPI1, indexTX*8 ); } if ( CurrentBufSPI1 == buf2 ) { ukladkabufTXSPI1 ( Buffer2TX_SPI1 );
DMA_Config ( Buffer2TX_SPI1, indexTX*8 ); } vTaskSuspend ( &xHandleSPI1 );
} } Код [/code]void DMA_Config ( uint8_t * Memory0BaseAddr, uint16_t size ) { DMA_InitTypeDef DMA_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
// Сброс настроек DMA каналов DMA_DeInit ( SPI_DMA_MASTER_Tx_DMA_Stream );
RCC_AHB1PeriphClockCmd ( SPI_DMA_MASTER_DMA_CLK, ENABLE );
DMA_DeInit(SPIx_TX_DMA_STREAM); /* Configure DMA Initialization Structure */ DMA_InitStructure.DMA_BufferSize = size; DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull; DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t) (&(SPIx->DR)); DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_Priority = DMA_Priority_High; /* Configure TX DMA */ DMA_InitStructure.DMA_Channel = SPIx_TX_DMA_CHANNEL; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)Memory0BaseAddr; DMA_Init(SPIx_TX_DMA_STREAM, &DMA_InitStructure);
// Configure the DMA interrupt priority NVIC_InitStructure.NVIC_IRQChannel = DMAx_Streamx_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init ( &NVIC_InitStructure );
SPI_I2S_ITConfig ( SPIx, SPI_I2S_IT_TXE, ENABLE );
DMA_ClearITPendingBit ( SPI_DMA_MASTER_Tx_DMA_Stream, SPI_DMA_MASTER_Tx_DMA_IT ); DMA_ClearFlag ( SPI_DMA_MASTER_Tx_DMA_Stream, SPI_DMA_MASTER_Tx_DMA_FLAG );
SPI_I2S_DMACmd ( SPI_DMA_MASTER, SPI_I2S_DMAReq_Tx, ENABLE ); DMA_ITConfig ( SPI_DMA_MASTER_Tx_DMA_Stream, DMA_IT_TC, ENABLE ); DMA_Cmd ( SPI_DMA_MASTER_Tx_DMA_Stream, ENABLE ); } знаю есть режим дабл-буфер в f411, но как его заюзать на SPL? дефайны: Код #define SPI_DMA_MASTER SPI1 #define SPI_DMA_MASTER_DMA DMA2 #define SPI_DMA_MASTER_DMA_CLK RCC_AHB1Periph_DMA2 #define SPI_DMA_MASTER_Tx_DMA_Stream DMA2_Stream5 #define SPI_DMA_MASTER_Tx_DMA_Channel DMA_Channel_3 #define SPI_DMA_MASTER_Tx_DMA_FLAG DMA_FLAG_TCIF5 #define SPI_DMA_MASTER_Tx_DMA_IT DMA_IT_TCIF5 #define DMAx_Streamx_IRQn DMA2_Stream5_IRQn
#define SPIx_DMA DMA2 #define SPIx_DMA_CLK RCC_AHB1Periph_DMA2 #define SPIx_TX_DMA_CHANNEL DMA_Channel_3 #define SPIx_TX_DMA_STREAM DMA2_Stream5 #define SPIx_TX_DMA_FLAG_TCIF DMA_FLAG_TCIF5
Сообщение отредактировал Volldemar - Aug 31 2017, 12:53
|
|
|
|
|
Sep 1 2017, 06:06
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342

|
Цитата(AHTOXA @ Aug 31 2017, 20:59)  После if ( CurrentBufSPI1 == buf1 ) нужен else. Иначе во втором if буфер переключается обратно. Спасибо за подсказку, но почему в прерывании не заходит в if?: Код if ( DMA_GetITStatus ( SPI_DMA_MASTER_Tx_DMA_Stream, DMA_IT_TCIF5 ) == SET )
|
|
|
|
|
Sep 1 2017, 15:43
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (AHTOXA @ Sep 1 2017, 18:07)  Вы запусакете третий канал, а проверяете почему-то пятый. Не, у них в старших "канал" - это номер входа запроса. Запускается пятый поток с запросами по третьему каналу: CODE #define SPI_DMA_MASTER_Tx_DMA_Stream DMA2_Stream5
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Sep 1 2017, 19:56
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(Volldemar @ Aug 31 2017, 15:24)  Надеюсь на конструктивный диалог, заранее спасибо. Похоже на FreeRTOS. Там с приоритетами прерываний нужно быть очень аккуратным. Не все функции можно использовать в обработчике. Мне кажется, что причиной может быть строчка Код uart2_putcharPoll ( 'I' );//, xNoBlock ); Для DMA у вас задан самый высокий приоритет Код // Configure the DMA interrupt priority NVIC_InitStructure.NVIC_IRQChannel = DMAx_Streamx_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init ( &NVIC_InitStructure ); - вы не имеете право пользоваться функциями ОС внутри такого обработчика.
|
|
|
|
|
Sep 4 2017, 05:58
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342

|
Цитата(adnega @ Sep 1 2017, 22:56)  Похоже на FreeRTOS. Это и есть оно. Цитата Там с приоритетами прерываний нужно быть очень аккуратным. Не все функции можно использовать в обработчике. Мне кажется, что причиной может быть строчка Код uart2_putcharPoll ( 'I' );//, xNoBlock ); Для DMA у вас задан самый высокий приоритет Код // Configure the DMA interrupt priority NVIC_InitStructure.NVIC_IRQChannel = DMAx_Streamx_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init ( &NVIC_InitStructure ); - вы не имеете право пользоваться функциями ОС внутри такого обработчика. - вы не имеете право пользоваться функциями ОС внутри такого обработчика.я об этом в курсе, но ф-ция uart2_putcharPoll не содержит вызовов ф-ций ОС: Код usart_err_t uart2_putcharPoll ( uint8_t byte ) { USART_SendData ( USART2, byte );
while ( USART_GetFlagStatus( USART2, USART_FLAG_TC ) == RESET );
return USART_OK; }/* end uart2_putchar */
Сообщение отредактировал Volldemar - Sep 4 2017, 06:01
|
|
|
|
|
Sep 4 2017, 06:12
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(Volldemar @ Sep 4 2017, 08:58)  я об этом в курсе А как же это в конце обработчика? Код xSemaphoreGiveFromISR ( xSemaphore_spi1, &xHigherPriorityTaskWoken ); xTaskResumeFromISR (&xHandleSPI1); uart2_putcharPoll ( 'E' );//, xNoBlock ); portEND_SWITCHING_ISR ( xHigherPriorityTaskWoken ); Попробуйте приоритет сделать ниже системного. Насчет Код while ( USART_GetFlagStatus( USART2, USART_FLAG_TC ) == RESET ); - это не лучшее решение ждать отправки в самом высокоуровневом прерывании. Лучше сделать для uart очередь и в idle ее опустошать. Если вам для отладки, то лучше светодиод на выводе МК.
|
|
|
|
|
Sep 4 2017, 06:15
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342

|
Цитата(adnega @ Sep 4 2017, 09:12)  А как же это в конце обработчика? Код xSemaphoreGiveFromISR ( xSemaphore_spi1, &xHigherPriorityTaskWoken ); xTaskResumeFromISR (&xHandleSPI1); uart2_putcharPoll ( 'E' );//, xNoBlock ); portEND_SWITCHING_ISR ( xHigherPriorityTaskWoken ); ничего криминального не вижу, увы  если что то есть, подскажите плиз.
|
|
|
|
|
Sep 4 2017, 07:19
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342

|
Цитата(adnega @ Sep 4 2017, 09:58)  Вы используете функции ОС в прерывании, у которого приоритет выше системного. какой уровень посоветуете установить? Имею ввиду конкретную цифру.
|
|
|
|
|
Sep 4 2017, 08:29
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(Volldemar @ Sep 4 2017, 10:19)  какой уровень посоветуете установить? Имею ввиду конкретную цифру. О, я рекомендую почитать. Очень хорошие статьи у Курница. На странице 40 раздел "Вложенность прерываний" и далее. Еще обсуждали тут. Есть на английском тут.
|
|
|
|
|
Sep 4 2017, 09:17
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342

|
Цитата(adnega @ Sep 4 2017, 11:29)  О, я рекомендую почитать. Очень хорошие статьи у Курница. На странице 40 раздел "Вложенность прерываний" и далее. Еще обсуждали тут. Есть на английском тут. По Вашим ссылкам на обсуждение: - из Вашего кода: Код NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = (uint8_t)(configKERNEL_INTERRUPT_PRIORITY >> 4); это обкатано?
|
|
|
|
|
Sep 4 2017, 10:32
|
Участник

Группа: Участник
Сообщений: 40
Регистрация: 27-01-17
Пользователь №: 95 184

|
У себя делал так, на STM32F4x9: CODE #include "globals.h" #include "SPIRoutines.h"
static uint8_t RxDummy; static uint8_t TxDummy;
static xSemaphoreHandle MEM_Complete; static xSemaphoreHandle SpiBusy;
static DMA_InitTypeDef DMA_InitStructure;
_SPI_CS_PIN_STRUCT CS_DevList[] = { { "FLASH", GPIO_Pin_14, GPIOC, RCC_AHB1Periph_GPIOC }, { "FRAM 1", GPIO_Pin_3, GPIOE, RCC_AHB1Periph_GPIOE }, { "FRAM 2", GPIO_Pin_4, GPIOE, RCC_AHB1Periph_GPIOE }, { "FRAM 3", GPIO_Pin_13, GPIOC, RCC_AHB1Periph_GPIOC }, { "FRAM 4", GPIO_Pin_8, GPIOI, RCC_AHB1Periph_GPIOI },
};
void InitSPI4(void) { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure;
// Тактирование модуля SPI, портов, DMA RCC_AHB1PeriphClockCmd(SPI_EXT_MEM_GPIO_RCC, ENABLE); RCC_APB2PeriphClockCmd(SPI_EXT_MEM_RCC, ENABLE); RCC_AHB1PeriphClockCmd(SPI_EXT_MEM_DMA_CLK, ENABLE);
//Настроим порты GPIO_InitStructure.GPIO_Pin = SPI_EXT_MEM_SCK | SPI_EXT_MEM_MOSI | SPI_EXT_MEM_MISO; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(SPI_EXT_MEM_GPIO, &GPIO_InitStructure);
GPIO_PinAFConfig(SPI_EXT_MEM_GPIO ,GPIO_PinSource2 ,GPIO_AF_SPI4 ); GPIO_PinAFConfig(SPI_EXT_MEM_GPIO ,GPIO_PinSource5 ,GPIO_AF_SPI4 ); GPIO_PinAFConfig(SPI_EXT_MEM_GPIO ,GPIO_PinSource6 ,GPIO_AF_SPI4 );
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
for (uint8_t i = 0; i < SPI_EXT_MEM_NUM_CS; i++) { RCC_AHB1PeriphClockCmd( CS_DevList[i].Rcc, ENABLE); GPIO_InitStructure.GPIO_Pin = CS_DevList[i].Pin; GPIO_Init(CS_DevList[i].Port, &GPIO_InitStructure); SPI_CS_High((List_CsDev)i); }
//Заполняем структуру с параметрами SPI модуля SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // полный дуплекс SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // передаем по 8 бит SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // Полярность и SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // фаза тактового сигнала SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // Управлять состоянием сигнала NSS программно SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4; // Предделитель SCK (APB2 90 MHz) SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // Первым отправляется старший бит SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // Режим - мастер SPI_Init(SPI_EXT_MEM, &SPI_InitStructure); // Настраиваем SPI1 // SPI_Cmd(SPI_EXT_MEM, ENABLE); // Включаем модуль
SPI_NSSInternalSoftwareConfig(SPI_EXT_MEM, SPI_NSSInternalSoft_Set);
SPI_I2S_DMACmd(SPI_EXT_MEM, SPI_I2S_DMAReq_Rx, ENABLE); SPI_I2S_DMACmd(SPI_EXT_MEM, SPI_I2S_DMAReq_Tx, ENABLE);
//настройка прерываний DMA //Прерывания только по Rx, когда байт уже ушел NVIC_InitStructure.NVIC_IRQChannel = SPI_EXT_MEM_Rx_DMA_IRQ; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = SPI_EXT_MEM_Rx_DMA_IRQ_PRIORITY; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);
DMA_StructInit(&DMA_InitStructure); DMA_InitStructure.DMA_Channel = SPI_EXT_MEM_DMA_Channel; DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI_EXT_MEM->DR; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; DMA_InitStructure.DMA_Priority = DMA_Priority_High; 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;
vSemaphoreCreateBinary(MEM_Complete); xSemaphoreTake(MEM_Complete, 0);
SpiBusy = xSemaphoreCreateMutex(); }
void SPI4_SetDMA_RxTx(uint32_t MemAddr ,uint16_t NumByte ,List_DMA_Mode Mode ) { xSemaphoreTake(SpiBusy, portMAX_DELAY);
DMA_DeInit(SPI_EXT_MEM_Rx_DMA_Stream); DMA_DeInit(SPI_EXT_MEM_Tx_DMA_Stream);
DMA_InitStructure.DMA_BufferSize = NumByte; if (Mode == DMA_MODE_TX || Mode == DMA_MODE_TX_FILL) { DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&RxDummy; //при записи пишем в переменную-пустышку без инкремента DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_Init(SPI_EXT_MEM_Rx_DMA_Stream, &DMA_InitStructure);
DMA_InitStructure.DMA_Memory0BaseAddr = MemAddr; if (Mode == DMA_MODE_TX) DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; else DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_Init(SPI_EXT_MEM_Tx_DMA_Stream, &DMA_InitStructure); } else { DMA_InitStructure.DMA_Memory0BaseAddr = MemAddr; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; DMA_Init(SPI_EXT_MEM_Rx_DMA_Stream, &DMA_InitStructure);
DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&TxDummy; //при чтении передаем переменную-пустышку без инкремента DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; DMA_Init(SPI_EXT_MEM_Tx_DMA_Stream, &DMA_InitStructure); } DMA_ITConfig(SPI_EXT_MEM_Rx_DMA_Stream, DMA_IT_TC, ENABLE);
DMA_Cmd(SPI_EXT_MEM_Rx_DMA_Stream, ENABLE); // Запускаем на прием DMA_Cmd(SPI_EXT_MEM_Tx_DMA_Stream, ENABLE); // Запускаем на передачу SPI_Cmd(SPI_EXT_MEM, ENABLE); // Включаем модуль (для одновременного старта RX/TX)
xSemaphoreTake(MEM_Complete, portMAX_DELAY); // Ждем пока отработает
while (DMA_GetCmdStatus(SPI_EXT_MEM_Tx_DMA_Stream) != DISABLE); while (DMA_GetCmdStatus(SPI_EXT_MEM_Rx_DMA_Stream) != DISABLE); SPI_Cmd(SPI_EXT_MEM, DISABLE); // Выключаем модуль
xSemaphoreGive(SpiBusy); }
//Завершение чтения(а оно возникает только после полной записи) DMA void DMA2_Stream0_IRQHandler(void) { static portBASE_TYPE xHigherPriorityTaskWoken; xHigherPriorityTaskWoken = pdFALSE;
if (DMA_GetITStatus(SPI_EXT_MEM_Rx_DMA_Stream ,SPI_EXT_MEM_Rx_DMA_FLAG )) { DMA_ClearITPendingBit(SPI_EXT_MEM_Rx_DMA_Stream, SPI_EXT_MEM_Rx_DMA_FLAG);
xSemaphoreGiveFromISR(MEM_Complete ,&xHigherPriorityTaskWoken ); if( xHigherPriorityTaskWoken == pdTRUE ) taskYIELD(); } }
void SPI_CS_Low(List_CsDev Device) { asm("nop"); GPIO_ResetBits(CS_DevList[Device].Port, CS_DevList[Device].Pin); asm("nop"); }
void SPI_CS_High(List_CsDev Device) { asm("nop"); GPIO_SetBits(CS_DevList[Device].Port, CS_DevList[Device].Pin); asm("nop"); }
CODE #ifndef SPI_ROUTINES_H #define SPI_ROUTINES_H
#define SPI_EXT_MEM SPI4 #define SPI_EXT_MEM_RCC RCC_APB2Periph_SPI4
#define SPI_EXT_MEM_GPIO GPIOE #define SPI_EXT_MEM_GPIO_RCC RCC_AHB1Periph_GPIOE #define SPI_EXT_MEM_SCK GPIO_Pin_2 #define SPI_EXT_MEM_MISO GPIO_Pin_5 #define SPI_EXT_MEM_MOSI GPIO_Pin_6
#define SPI_EXT_MEM_NUM_CS 5
#define SPI_EXT_MEM_DMA_CLK RCC_AHB1Periph_DMA2 #define SPI_EXT_MEM_DMA_Channel DMA_Channel_4 #define SPI_EXT_MEM_Rx_DMA_Stream DMA2_Stream0 #define SPI_EXT_MEM_Tx_DMA_Stream DMA2_Stream1
#define SPI_EXT_MEM_Rx_DMA_IRQ DMA2_Stream0_IRQn #define SPI_EXT_MEM_Rx_DMA_FLAG DMA_IT_TCIF0 #define SPI_EXT_MEM_Rx_DMA_IRQ_PRIORITY 15
typedef enum { EXT_MEM_FLASH = 0, // AT45DB641E EXT_MEM_FRAM1, EXT_MEM_FRAM2, EXT_MEM_FRAM3, EXT_MEM_FRAM4, }List_CsDev;
typedef struct { const uint8_t *Str; uint16_t Pin; GPIO_TypeDef *Port; uint32_t Rcc; } _SPI_CS_PIN_STRUCT;
typedef enum { DMA_MODE_RX=1, // читаем данные DMA_MODE_TX, // пишем данные DMA_MODE_TX_FILL, // Заполняем одним и тем же }List_DMA_Mode;
extern void InitSPI4(void);
extern void SPI_CS_Low(List_CsDev Device); extern void SPI_CS_High(List_CsDev Device);
extern void SPI4_SetDMA_RxTx(uint32_t MemAddr ,uint16_t NumByte ,List_DMA_Mode Mode );
extern _SPI_CS_PIN_STRUCT CS_DevList[];
#endif
Для чтения/записи в нужный CS необходимо лишь: Код SPI_CS_Low(EXT_MEM_FLASH); SPI4_SetDMA_RxTx((uint32_t)TxBuf, 1,DMA_MODE_TX); SPI4_SetDMA_RxTx((uint32_t)RxBuf, 9,DMA_MODE_RX); SPI_CS_High(EXT_MEM_FLASH); Естественно вызывать только из тасков FreeRTOS, т.е. используется ожидания завершения передачи через семафор. В вашем прерывании нет необходимости вызывать: Код DMA_Cmd ( SPI_DMA_MASTER_Tx_DMA_Stream, DISABLE ); Т.к. Stream автоматически выключается после окончания передачи, что явно указано в ДШ:
UPD: И еще важная мелочь - т.к. вы используете только Tx на DMA, фактически, прерывание не гарантирует того, что все данные вышли с MOSI-линии. Это значит лишь то, что DMA закончил работу, и переправил все байты в регистр данных SPI, который буферизирован. Для однозначного отслеживания окончания передачи следует дожидаться флага SPI_SR_BSY в статусном регистре SPI. Это не особо заметно на маленьких скоростях, но на больших это вылазит тут же. Помню долго голову ломал, почему , при снятии CS после срабатывания DMA прерывания по Tx, фактически на осциллографе CS снимался посередине последнего байта, естественно данные портились.
Сообщение отредактировал Hold - Sep 4 2017, 10:51
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|