реклама на сайте
подробности

 
 
4 страниц V   1 2 3 > »   
Reply to this topicStart new topic
> stm32f411 spi1+DMA, непрерывная выдача данных
Volldemar
сообщение Aug 31 2017, 12:24
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Aug 31 2017, 17:59
Сообщение #2


фанат дивана
******

Группа: Свой
Сообщений: 3 326
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



После
if ( CurrentBufSPI1 == buf1 )
нужен else. Иначе во втором if буфер переключается обратно.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Volldemar
сообщение Sep 1 2017, 06:06
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 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 )
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Sep 1 2017, 15:07
Сообщение #4


фанат дивана
******

Группа: Свой
Сообщений: 3 326
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



Код
#define SPI_DMA_MASTER_Tx_DMA_Channel    DMA_Channel_3
#define SPI_DMA_MASTER_Tx_DMA_FLAG        DMA_FLAG_TCIF5

Вы запусакете третий канал, а проверяете почему-то пятый.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 1 2017, 15:43
Сообщение #5


Гуру
******

Группа: Модераторы
Сообщений: 8 093
Регистрация: 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)
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Sep 1 2017, 19:47
Сообщение #6


фанат дивана
******

Группа: Свой
Сообщений: 3 326
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684



А, точно, забыл уже, что там ещё один уровень добавили.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
adnega
сообщение Sep 1 2017, 19:56
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 2 362
Регистрация: 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 );

- вы не имеете право пользоваться функциями ОС внутри такого обработчика.
Go to the top of the page
 
+Quote Post
Volldemar
сообщение Sep 4 2017, 05:58
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
adnega
сообщение Sep 4 2017, 06:12
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 2 362
Регистрация: 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 ее опустошать.
Если вам для отладки, то лучше светодиод на выводе МК.
Go to the top of the page
 
+Quote Post
Volldemar
сообщение Sep 4 2017, 06:15
Сообщение #10


Частый гость
**

Группа: Участник
Сообщений: 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 );

ничего криминального не вижу, увы sad.gif
если что то есть, подскажите плиз.
Go to the top of the page
 
+Quote Post
adnega
сообщение Sep 4 2017, 06:58
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 2 362
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Цитата(Volldemar @ Sep 4 2017, 09:15) *
ничего криминального не вижу, увы sad.gif
если что то есть, подскажите плиз.

Вы используете функции ОС в прерывании, у которого приоритет выше системного.
Go to the top of the page
 
+Quote Post
Volldemar
сообщение Sep 4 2017, 07:19
Сообщение #12


Частый гость
**

Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342



Цитата(adnega @ Sep 4 2017, 09:58) *
Вы используете функции ОС в прерывании, у которого приоритет выше системного.

какой уровень посоветуете установить? Имею ввиду конкретную цифру.
Go to the top of the page
 
+Quote Post
adnega
сообщение Sep 4 2017, 08:29
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 2 362
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Цитата(Volldemar @ Sep 4 2017, 10:19) *
какой уровень посоветуете установить? Имею ввиду конкретную цифру.

О, я рекомендую почитать. Очень хорошие статьи у Курница.
На странице 40 раздел "Вложенность прерываний" и далее. Еще обсуждали тут.
Есть на английском тут.
Go to the top of the page
 
+Quote Post
Volldemar
сообщение Sep 4 2017, 09:17
Сообщение #14


Частый гость
**

Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342



Цитата(adnega @ Sep 4 2017, 11:29) *
О, я рекомендую почитать. Очень хорошие статьи у Курница.
На странице 40 раздел "Вложенность прерываний" и далее. Еще обсуждали тут.
Есть на английском тут.

По Вашим ссылкам на обсуждение:
- из Вашего кода:
Код
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = (uint8_t)(configKERNEL_INTERRUPT_PRIORITY >> 4);
это обкатано?
Go to the top of the page
 
+Quote Post
Hold
сообщение Sep 4 2017, 10:32
Сообщение #15


Участник
*

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post

4 страниц V   1 2 3 > » 
Reply to this topicStart new topic
3 чел. читают эту тему (гостей: 3, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd November 2017 - 10:50
Рейтинг@Mail.ru


Страница сгенерированна за 0.01403 секунд с 7
ELECTRONIX ©2004-2016