Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: stm32f411 spi1+DMA
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
Volldemar
Привожу код что и как делаю, вопрос в том, что в прерывание ДМА входит, а вот уже в обработчике прерывания в 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
AHTOXA
После
if ( CurrentBufSPI1 == buf1 )
нужен else. Иначе во втором if буфер переключается обратно.
Volldemar
Цитата(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 )
AHTOXA
Код
#define SPI_DMA_MASTER_Tx_DMA_Channel    DMA_Channel_3
#define SPI_DMA_MASTER_Tx_DMA_FLAG        DMA_FLAG_TCIF5

Вы запусакете третий канал, а проверяете почему-то пятый.
Сергей Борщ
QUOTE (AHTOXA @ Sep 1 2017, 18:07) *
Вы запусакете третий канал, а проверяете почему-то пятый.
Не, у них в старших "канал" - это номер входа запроса. Запускается пятый поток с запросами по третьему каналу:
CODE
#define SPI_DMA_MASTER_Tx_DMA_Stream    DMA2_Stream5
AHTOXA
А, точно, забыл уже, что там ещё один уровень добавили.
adnega
Цитата(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 );

- вы не имеете право пользоваться функциями ОС внутри такого обработчика.
Volldemar
Цитата(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 */
adnega
Цитата(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 ее опустошать.
Если вам для отладки, то лучше светодиод на выводе МК.
Volldemar
Цитата(adnega @ Sep 4 2017, 09:12) *
А как же это в конце обработчика?
Код
   xSemaphoreGiveFromISR ( xSemaphore_spi1, &xHigherPriorityTaskWoken );
    xTaskResumeFromISR (&xHandleSPI1);
    uart2_putcharPoll ( 'E' );//, xNoBlock );
    portEND_SWITCHING_ISR ( xHigherPriorityTaskWoken );

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

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

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

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

По Вашим ссылкам на обсуждение:
- из Вашего кода:
Код
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = (uint8_t)(configKERNEL_INTERRUPT_PRIORITY >> 4);
это обкатано?
Hold
У себя делал так, на 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 снимался посередине последнего байта, естественно данные портились.
Volldemar
[quote]
Т.к. Stream автоматически выключается после окончания передачи, что явно указано в ДШ:
Нажмите для просмотра прикрепленного файла
Из-за этого незаходит в иф?
Код
if ( DMA_GetITStatus ( SPI_DMA_MASTER_Tx_DMA_Stream, DMA_IT_TCIF5 ) == SET )

Сергей Борщ
QUOTE (Hold @ Sep 4 2017, 13:32) *
Для однозначного отслеживания окончания передачи следует дожидаться флага SPI_SR_BSY в статусном регистре SPI.
Несомненным достижением инженеров ST можно назвать отсутствие прерывания на этот флаг.
Volldemar
Цитата(Сергей Борщ @ Sep 4 2017, 15:02) *
Несомненным достижением инженеров ST можно назвать отсутствие прерывания на этот флаг.

А разве прерывание:
Код
SPI_I2S_IT_TXE: Tx buffer empty interrupt mask

это не оно? т.е. по опустошению передающего буфера генерится прерывание и сраюатывает этотфлаг
jcxz
Цитата(Volldemar @ Sep 4 2017, 15:09) *
это не оно? т.е. по опустошению передающего буфера генерится прерывание и сраюатывает этотфлаг

Не оно. Пустой буфер != окончание передачи.
Hold
Цитата(Сергей Борщ @ Sep 4 2017, 19:02) *
Несомненным достижением инженеров ST можно назвать отсутствие прерывания на этот флаг.

Помню долго недоумевал, как же отслеживать окончание передачи только по Tx, используя прерывания. Была уже мысль включить Rx канал DMA, без физического подключения Rx, и работать по нему. Но руки так и не дошли.
Сергей Борщ
QUOTE (Hold @ Sep 5 2017, 07:09) *
Была уже мысль включить Rx канал DMA, без физического подключения Rx, и работать по нему.
Так и приходится. Попутно посылая лучи поноса авторам этого периферийного модуля. В I2C им тоже что-то подобное удалось.
Hold
SPI, по сравнению с I2C, еще относительно безглючный модуль. I2C так и не удалось корректно заставить работать на прерываниях. Точнее он работает, но в какой-то момент, после старт-бита зависает. Обмен у нас редкий, так что перед каждым обменом полностью ресетим модуль. Но это уже оффтоп.
adnega
Цитата(Hold @ Sep 5 2017, 09:29) *
какой-то момент, после старт-бита зависает

В результате помехи устройство может недосчитаться CLK и давить линию SDA своим ACK.
Перед формированием условия START нужно убедиться, что SDA в 1, иначе подергать CLK.
jcxz
Цитата(Hold @ Sep 5 2017, 09:29) *
SPI, по сравнению с I2C, еще относительно безглючный модуль. I2C так и не удалось корректно заставить работать на прерываниях. Точнее он работает, но в какой-то момент, после старт-бита зависает. Обмен у нас редкий, так что перед каждым обменом полностью ресетим модуль. Но это уже оффтоп.

При отсутствии помех?
У меня устройство на STM32F429. Работает интенсивно по I2C (FRAM + RTC + др.). При отсутствии помех работает отлично: запускал тесты с непрерывным интенсивным обменом с FRAM-памятью длительностью до 12часов непрерывно - ни одного сбоя. Работа по прерываниям + DMA.
Но при включении мощной радиочастотной нагрузки на плате, начинаются периодические сбои по I2C (в основном - с одним из I2C-слэйвов). Некоторыми мерами удалось значительно снизить их частоту.
Так что у Вас одно из двух: или помехи по шине (проблемы в схемотехнике), или баги в ПО. А модуль I2C тут скорее всего не при чём.
Ссылка на топик, где я описывал свою проблему и процесс борьбы с ней: https://electronix.ru/forum/index.php?showt...141285&st=0

PS: Да - и если дело в помехах, то какой смысл в сбросе I2C-модуля перед обменом? Ведь помеха может быть во время транзакции. Это поможет только при багах в ПО. Но тогда это - костыль на кривой код.
Volldemar
Ребят, канешна спасибо за инфу, очень пригодится в будущем, но тема про SPI+DMA, точнее double buffer DMA+SPI, задача- необходимо реализовать непрерывный вывод в TX SPI потока данных, которые потом поступают на ВЧ модулятор и ессно потом на антенну, т.е. своеобразный передатчик, а непрерывная выдача необходима для того, что бы небыло так называемой "разрыва фазы", что бы приемник мог принять и демодулировать инфу. Вот помогли бы мне с этим, буду премного благодарен!
adnega
Цитата(Volldemar @ Sep 5 2017, 10:23) *
Вот помогли бы мне с этим, буду премного благодарен!

Значит поток у вас непрерывный. Тут все просто - делаете кольцевой буфер на DMA и забываете вообще про SPI.
Готовите в прерываниях DMA HT и TC новую половину данных. SPI лучше сделать 16 бит, если выдаете с частотой
не сильно меньше AHB. Я делал на стареньком STM32F103 вывод на VGA-монитор - очень похожая задачка.
Volldemar
Цитата(adnega @ Sep 5 2017, 10:56) *
Значит поток у вас непрерывный. Тут все просто - делаете кольцевой буфер на DMA и забываете вообще про SPI.
Готовите в прерываниях DMA HT и TC новую половину данных. SPI лучше сделать 16 бит, если выдаете с частотой
не сильно меньше AHB. Я делал на стареньком STM32F103 вывод на VGA-монитор - очень похожая задачка.

у меня данные байтовые, т.е. и выдача в SPI байтовая и строго выдержанная тактовая в 1 МГц, но это уже в настройках самого SPI реализовано.

в F411 есть интереный момент Double Buffer mode DMA, вот только примеров как это заюзать нет, а у меня не хочет работать sad.gif
Hold
Цитата(jcxz @ Sep 5 2017, 13:58) *
При отсутствии помех?
У меня устройство на STM32F429. Работает интенсивно по I2C (FRAM + RTC + др.). При отсутствии помех работает отлично: запускал тесты с непрерывным интенсивным обменом с FRAM-памятью длительностью до 12часов непрерывно - ни одного сбоя. Работа по прерываниям + DMA.
Но при включении мощной радиочастотной нагрузки на плате, начинаются периодические сбои по I2C (в основном - с одним из I2C-слэйвов). Некоторыми мерами удалось значительно снизить их частоту.
Так что у Вас одно из двух: или помехи по шине (проблемы в схемотехнике), или баги в ПО. А модуль I2C тут скорее всего не при чём.
Ссылка на топик, где я описывал свою проблему и процесс борьбы с ней: https://electronix.ru/forum/index.php?showt...141285&st=0

PS: Да - и если дело в помехах, то какой смысл в сбросе I2C-модуля перед обменом? Ведь помеха может быть во время транзакции. Это поможет только при багах в ПО. Но тогда это - костыль на кривой код.

Понимаю что это оффтоп, но раз уж заговорили, прикладываю свою библиотеку I2C. Не претендую на идеальность, но она работает на F1 и F4. И да, есть сброс. Помехи исключены, смотрели осциллом. Проблема всегда появляется именно после первой транзакции на чтение/запись. Не всегда на второй транзакции, но всегда после первой. Регистры I2C при зависоне соответствуют регистрам при нормальной работе, Первая транзакция всегда проходит идеально, ошибок нет, были бы помехи,они бы и первую портили. При зависоне, I2C не генерит никакой ошибки, просто виснет после старт-бита, притягивая линию к 0. И это проблема не слейва, т.к. проблема проявляется и при отсутствующем слейве. Резисторы по 3К, длина линии на плате не более 50-100 мм, рядом силовухи нет.
CODE

#include "globals.h"
#include "I2C3Routines.h"

volatile uint8_t AddrSlave; //адрес слейва
volatile uint32_t AddrReg; //адрес регистра слейва, с которым хотим что-либо сделать
volatile uint8_t ByteCount; //кол-во байт на чтение-запись
volatile uint8_t AddrByteCnt; //кол-во байт адреса
volatile uint8_t RxBTF; //флажок
volatile uint8_t* I2CBuffer; //указатель на буфер чтения/записи
volatile uint8_t I2CRestart; //флаг повторного старта
volatile List_I2C_Modes I2C_Mode; //режим работы I2C
volatile List_I2C_Result I2C_Res; //Результат операции I2C

xSemaphoreHandle I2C_Complete = NULL; //данные записаны/прочитаны
xSemaphoreHandle I2C3Mutex = NULL; //Мьютекс

List_I2C_Result I2C3Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;

#ifdef GPIO_CM3
//Тактирование
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(I2C_NUMB_RCC ,ENABLE );
RCC_APB2PeriphClockCmd(I2C_NUMB_GPIO_RCC ,ENABLE );
//Настройка пинов
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL | I2C_NUMB_SDA;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(I2C_NUMB_GPIO, &GPIO_InitStructure);
#elif defined GPIO_CM4
// Тактирование

if (I2C3Mutex != NULL) // При повторной инициализации
{
I2C_ITConfig(I2C_NUMB, (I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR), DISABLE);

RCC_APB1PeriphClockCmd(I2C_NUMB_RCC, DISABLE );

//настройка прерываний
NVIC_InitStructure.NVIC_IRQChannel = I2C_NUMB_IRQ_EV;
NVIC_InitStructure.NVIC_IRQChannelCmd = DISABLE;
NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = I2C_NUMB_IRQ_ER;
NVIC_Init(&NVIC_InitStructure);

// Сбросим пины в дефолт
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
GPIO_Init(I2C_NUMB_GPIO_SCL, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_Init(I2C_NUMB_GPIO_SDA, &GPIO_InitStructure);

}
else // При первой
{
I2C3Mutex = xSemaphoreCreateMutex();

vSemaphoreCreateBinary(I2C_Complete);
xSemaphoreTake(I2C_Complete, 0);

RCC_AHB1PeriphClockCmd(I2C_NUMB_GPIO_SCL_RCC ,ENABLE );
RCC_AHB1PeriphClockCmd(I2C_NUMB_GPIO_SDA_RCC ,ENABLE );
}

RCC_APB1PeriphClockCmd(I2C_NUMB_RCC ,ENABLE );

// Настройка пинов
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
GPIO_Init(I2C_NUMB_GPIO_SCL, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_Init(I2C_NUMB_GPIO_SDA, &GPIO_InitStructure);

GPIO_PinAFConfig(I2C_NUMB_GPIO_SCL, GPIO_PinSource8, GPIO_AF_I2C3); //SCL
GPIO_PinAFConfig(I2C_NUMB_GPIO_SDA, GPIO_PinSource9, GPIO_AF_I2C3); //SDA
#endif

//Настройка I2C
I2C_DeInit(I2C_NUMB);
I2C_SoftwareResetCmd(I2C_NUMB, ENABLE);
I2C_SoftwareResetCmd(I2C_NUMB, DISABLE);

I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED;
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
I2C_InitStructure.I2C_OwnAddress1 = I2C_MY_ADDRESS;
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C_NUMB, &I2C_InitStructure);

I2C_Cmd(I2C_NUMB, ENABLE);

//Проверим, что шина не зависла
if(I2C_GetFlagStatus(I2C_NUMB, I2C_FLAG_BUSY)) //шина зависла, надо подергать SCL
{
uint8_t countClk = 0;

I2C_Cmd(I2C_NUMB, DISABLE); //отключим I2C
//перенастраиваем пины
#ifdef GPIO_CM3
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(I2C_NUMB_GPIO, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(I2C_NUMB_GPIO, &GPIO_InitStructure);
#elif defined GPIO_CM4
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
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;
GPIO_Init(I2C_NUMB_GPIO_SCL, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(I2C_NUMB_GPIO_SDA, &GPIO_InitStructure);
#endif
SCL_HI;
while(!CHECK_SDA) //дергаем SCL, пока SDA не поднимется
{
vTaskDelay(1);
SCL_LO;
vTaskDelay(1);
SCL_HI;
if (countClk++ == 100) //ничего не вышло, отключим всё, вернём ошибку
{
#ifdef GPIO_CM3
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA | I2C_NUMB_SCL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(I2C_NUMB_GPIO ,&GPIO_InitStructure );
#elif defined GPIO_CM4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;

GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
GPIO_Init(I2C_NUMB_GPIO_SCL, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_Init(I2C_NUMB_GPIO_SDA, &GPIO_InitStructure);
#endif
I2C_DeInit(I2C_NUMB);
RCC_APB1PeriphClockCmd(I2C_NUMB_RCC ,DISABLE );
return I2C_ERR_BUS;
}
}
//вернем настройки обратно
#ifdef GPIO_CM3
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL | I2C_NUMB_SDA;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
GPIO_Init(I2C_NUMB_GPIO ,&GPIO_InitStructure );
#elif defined GPIO_CM4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;

GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SCL;
GPIO_Init(I2C_NUMB_GPIO_SCL, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = I2C_NUMB_SDA;
GPIO_Init(I2C_NUMB_GPIO_SDA, &GPIO_InitStructure);
#endif
I2C_Cmd(I2C_NUMB, ENABLE);
}

//настройка прерываний
NVIC_InitStructure.NVIC_IRQChannel = I2C_NUMB_IRQ_EV;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = I2C_NUMB_EV_IRQ_PRIORITY;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = I2C_NUMB_IRQ_ER;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = I2C_NUMB_ER_IRQ_PRIORITY;
NVIC_Init(&NVIC_InitStructure);

vTaskDelay(3);

return I2C_CMD_OK;
}
List_I2C_Result I2C_Master_BufferRead(uint8_t SlaveAddress ,uint8_t* pBuffer ,uint8_t NumByteToRead )
{
I2C3Init();
RxBTF = 0;
I2CRestart = 0;
I2C_Mode = I2C_MODE_READ;
AddrSlave = (SlaveAddress << 1);
I2CBuffer = pBuffer;
ByteCount = NumByteToRead;
if (NumByteToRead == 2) I2C_NACKPositionConfig(I2C_NUMB, I2C_NACKPosition_Next);
else I2C_NACKPositionConfig(I2C_NUMB, I2C_NACKPosition_Current);
I2C_ITConfig(I2C_NUMB, (I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR), ENABLE);
I2C_AcknowledgeConfig(I2C_NUMB, ENABLE);
I2C_GenerateSTART(I2C_NUMB, ENABLE); //Поехали

if (xSemaphoreTake(I2C_Complete, I2C_TIMEOUT) == pdTRUE) return I2C_Res;
else return I2C_ERR_UNKNOWN;
}
List_I2C_Result I2C_Master_BufferWrite(uint8_t SlaveAddress ,uint8_t RegAddress , uint8_t* pBuffer ,uint8_t NumByteToWrite )
{
I2C3Init();
RxBTF = 0;
I2CRestart = 0;
I2C_Mode = I2C_MODE_WRITE;
AddrSlave = (SlaveAddress << 1);
AddrReg = RegAddress;
I2CBuffer = pBuffer;
ByteCount = NumByteToWrite;
I2C_ITConfig(I2C_NUMB, (I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR), ENABLE);
I2C_AcknowledgeConfig(I2C_NUMB, ENABLE);
I2C_GenerateSTART(I2C_NUMB, ENABLE); //Поехали

if (xSemaphoreTake(I2C_Complete, I2C_TIMEOUT) == pdTRUE) return I2C_Res;
else return I2C_ERR_UNKNOWN;
}
List_I2C_Result I2C_Master_BufferWriteRead(uint8_t SlaveAddress ,uint32_t RegAddress , uint8_t* pBuffer ,uint8_t NumByteToRead )
{
I2C3Init();
RxBTF = 0;
I2CRestart = 0;
I2C_Mode = I2C_MODE_WRITEREAD;
AddrSlave = (SlaveAddress << 1);
AddrReg = RegAddress & 0x7FFFFFFF;
AddrByteCnt = (RegAddress >> 24) & 0x03;
I2CBuffer = pBuffer;
ByteCount = NumByteToRead;
if (NumByteToRead == 2) I2C_NACKPositionConfig(I2C_NUMB, I2C_NACKPosition_Next);
I2C_ITConfig(I2C_NUMB, (I2C_IT_EVT | I2C_IT_BUF | I2C_IT_ERR), ENABLE);
I2C_AcknowledgeConfig(I2C_NUMB, ENABLE);
I2C_GenerateSTART(I2C_NUMB, ENABLE); //Поехали

if (xSemaphoreTake(I2C_Complete, I2C_TIMEOUT) == pdTRUE) return I2C_Res;
else return I2C_ERR_UNKNOWN;
}

//IRQ Event - Method 2 (DS - Master Receive)
void I2C3_EV_IRQHandler(void)
{
static portBASE_TYPE xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
switch (I2C_GetLastEvent(I2C_NUMB))
{
case I2C_EVENT_MASTER_MODE_SELECT: //EV5 Послали старт, теперь надо послать адрес слейва
{
if(I2CRestart || (I2C_Mode == I2C_MODE_READ))
{
I2C_NUMB->DR = AddrSlave | 0x01;
}
else
{
I2C_NUMB->DR = AddrSlave;
}
break;
}
case I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED: //EV6 Послали SlaveAddr7bit + R
{
if (ByteCount == 1)
{
I2C_NUMB->CR1 &=~I2C_CR1_ACK; //отключаем ACK после чтения
I2C_NUMB->CR1 |= I2C_CR1_STOP;
}
else if (ByteCount == 2)
{
I2C_NUMB->CR1 &=~I2C_CR1_ACK; //отключаем ACK после чтения
}
RxBTF = 1;
I2C_NUMB->CR2 |= I2C_CR2_ITBUFEN; //включим RxNE/TxE для передачи байт
break;
}
case I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: //EV6 Послали SlaveAddr7bit + W
{
if (I2C_Mode == I2C_MODE_WRITEREAD) //если попали сюда в режиме чтения, значит делаем повторный старт
{
if(!(--AddrByteCnt)) //Адрес из одного байта, шлем повторный старт
{
I2CRestart = 1;
I2C_NUMB->CR2 &= ~I2C_CR2_ITBUFEN; //Отключим TxE для передачи адреса (чтобы не попадать в EV8)
I2C_NUMB->DR = (uint8_t)AddrReg; //Шлем адрес регистра
I2C_NUMB->CR1 |= I2C_CR1_START; //отправится после завершения отправки адреса
}
else //надо отправить еще байты адреса
{
I2C_NUMB->DR = (uint8_t)AddrReg; //Шлем первый байт адреса
AddrReg>>=8;
}
break;
}
if (I2C_Mode == I2C_MODE_WRITE) //если режим записи
{
if(!ByteCount) //Нет байт на отправку
{
I2C_NUMB->CR2 &= ~I2C_CR2_ITBUFEN; //Отключим TxE для передачи последнего байта (чтобы не попадать в EV8)
}
I2C_NUMB->DR = (uint8_t)AddrReg; //Шлем адрес регистра
}
break;
}
case I2C_EVENT_MASTER_MODE_ADDRESS10: //EV9 Послали SlaveAddr3bit (заголовок 10-ти битного адреса)
{
asm("nop");
break;
}
case I2C_EVENT_MASTER_BYTE_RECEIVED: //EV7 Получили байт, надо прочитать
{
if (ByteCount-- == 2) // пред-последний байт
{
I2C_NUMB->CR1 &=~I2C_CR1_ACK; // отключаем ACK после чтения
I2C_NUMB->CR1 |= I2C_CR1_STOP; // говорим Стоп
}
*I2CBuffer++ = I2C_NUMB->DR; //пишем в буфер
break;
}
case I2C_EVENT_MASTER_BYTE_TRANSMITTING: //EV8 Пустой буфер на передачу (байт передается), можно кинуть еще байт в буфер
{
if(!I2CRestart) //Отправляем байты адреса только до рестарта
{
if(!(--AddrByteCnt)) // Отправляем последний байт адреса, шлем повторный старт
{
I2C_NUMB->CR2 &= ~I2C_CR2_ITBUFEN; //Отключим TxE для передачи адреса (чтобы не попадать в EV8)
}
else //надо отправить еще байты адреса
{
I2C_NUMB->DR = (uint8_t)AddrReg; //Шлем следующий байт адреса
AddrReg>>=8;
}
}
if(I2C_Mode == I2C_MODE_WRITE) //байт данных ушел, шлем следующий
{
if(!(--ByteCount)) //последний байт
{
I2C_NUMB->CR2 &= ~I2C_CR2_ITBUFEN; //Отключим TxE для передачи последнего байта (чтобы не попадать в EV8)
}
I2C_NUMB->DR = *I2CBuffer++;
}
break;
}
case I2C_EVENT_MASTER_BYTE_TRANSMITTED: //EV8_2 (DR и shift регистры) FIFO пустой (при передаче) FIFO полный (при приеме)
{
if(I2C_Mode == I2C_MODE_WRITEREAD && !I2CRestart)
{
I2CRestart = 1;
I2C_NUMB->DR = (uint8_t)AddrReg; //Шлем адрес регистра
I2C_NUMB->CR1 |= I2C_CR1_START; //отправится после завершения отправки адреса
break;
}
if(I2C_Mode == I2C_MODE_WRITE) //байт данных ушел, шлем следующий
{
if(!ByteCount) //всё отправили
{
I2C_NUMB->CR1 |= I2C_CR1_STOP; //говорим Стоп
I2C_Res = I2C_CMD_OK;
xSemaphoreGiveFromISR(I2C_Complete ,&xHigherPriorityTaskWoken );
if( xHigherPriorityTaskWoken == pdTRUE ) taskYIELD();
break;
}
}
if(((I2C_Mode == I2C_MODE_WRITEREAD) || (I2C_Mode == I2C_MODE_READ)) && RxBTF) //входной буфер забит, надо читать - !!НЕ ПРОВЕРЯЛОСЬ(написано согласно ДШ)!!
{
if (ByteCount == 3) // осталось прочитать 3 байта
{
I2C_NUMB->CR1 &=~I2C_CR1_ACK; //отключаем ACK после чтения
*I2CBuffer++ = I2C_NUMB->DR; //пишем в буфер

I2C_NUMB->CR1 |= I2C_CR1_STOP; //говорим Стоп
*I2CBuffer++ = I2C_NUMB->DR; //пишем в буфер

ByteCount-= 2;
}
if (ByteCount == 2) // осталось прочитать 2 байта
{
I2C_NUMB->CR1 |= I2C_CR1_STOP; //говорим Стоп
*I2CBuffer++ = I2C_NUMB->DR; //пишем в буфер
*I2CBuffer++ = I2C_NUMB->DR; //пишем в буфер
ByteCount-= 2;
}
}
break;
}
default: break;
}
if (!ByteCount && ((I2C_Mode == I2C_MODE_WRITEREAD) || (I2C_Mode == I2C_MODE_READ))) //всё прочитали
{
I2C_Res = I2C_CMD_OK;
xSemaphoreGiveFromISR(I2C_Complete ,&xHigherPriorityTaskWoken );
if( xHigherPriorityTaskWoken == pdTRUE ) taskYIELD();
}
}

//IRQ Error
void I2C3_ER_IRQHandler(void)
{
static portBASE_TYPE xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE;
if(I2C_GetITStatus(I2C_NUMB, I2C_FLAG_SMBALERT)) //SMBus Alert
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_FLAG_SMBALERT);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: SMB Alert\r\n");
#endif
I2C_Res = I2C_ERR_SMBALERT;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_TIMEOUT)) //Timeout/Tlow error
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_TIMEOUT);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: Timeout\r\n");
#endif
I2C_Res = I2C_ERR_TIMEOUT;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_PECERR)) //PEC Error
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_PECERR);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: PEC Error\r\n");
#endif
I2C_Res = I2C_ERR_PEC;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_OVR)) //Overrun/Underrun
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_OVR);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: Overrun/Underrun\r\n");
#endif
I2C_Res = I2C_ERR_OVR;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_AF)) //Acknowledge failure
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_AF);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: Acknowledge failure\r\n");
#endif
I2C_Res = I2C_ERR_NAK;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_ARLO)) //Arbitration loss
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_ARLO);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: Arbitration loss\r\n");
#endif
I2C_Res = I2C_ERR_ARLO;
}
if(I2C_GetITStatus(I2C_NUMB, I2C_IT_BERR)) //Bus error
{
I2C_ClearITPendingBit(I2C_NUMB, I2C_IT_BERR);
#ifdef I2C_DEBUG_INFO
UsartDebugSendStringPoll((const uint8_t*)"I2C Err: Bus error\r\n");
#endif
I2C_Res = I2C_ERR_BUS;
}
xSemaphoreGiveFromISR(I2C_Complete ,&xHigherPriorityTaskWoken ); // отдадим
if( xHigherPriorityTaskWoken == pdTRUE ) taskYIELD();
}


CODE

#ifndef I2C_ROUTINES_H
#define I2C_ROUTINES_H

//#define GPIO_CM3
#define GPIO_CM4

#define I2C_DEBUG_INFO // Выводить отладку в UART

#define I2C_NUMB I2C3
#define I2C_NUMB_RCC RCC_APB1Periph_I2C3
#define I2C_NUMB_IRQ_EV I2C3_EV_IRQn
#define I2C_NUMB_IRQ_ER I2C3_ER_IRQn

#define I2C_NUMB_GPIO_SCL GPIOA
#define I2C_NUMB_GPIO_SCL_RCC RCC_AHB1Periph_GPIOA
#define I2C_NUMB_SCL GPIO_Pin_8

#define I2C_NUMB_GPIO_SDA GPIOC
#define I2C_NUMB_GPIO_SDA_RCC RCC_AHB1Periph_GPIOC
#define I2C_NUMB_SDA GPIO_Pin_9


// не ставь выше ядра FreeRTOS!
#define I2C_NUMB_EV_IRQ_PRIORITY 6 //приоритет прерываний Events
#define I2C_NUMB_ER_IRQ_PRIORITY 7 //приоритет прерываний Error

#define I2C_SPEED 400000
#define I2C_MY_ADDRESS 0x7F //не используем

#define I2C_TIMEOUT 500 //Таймаут на ошибку

#define SCL_LO do \
{ \
GPIO_ResetBits(I2C_NUMB_GPIO_SCL, I2C_NUMB_SCL); \
}while(0)
#define SCL_HI do \
{ \
GPIO_SetBits(I2C_NUMB_GPIO_SCL, I2C_NUMB_SCL); \
}while(0)

#define CHECK_SDA (GPIO_ReadInputDataBit(I2C_NUMB_GPIO_SDA,I2C_NUMB_SDA))


// Режим i2c
typedef enum
{
I2C_MODE_READ=1, //чтение
I2C_MODE_WRITE, //запись
I2C_MODE_WRITEREAD, //Чтение с заносом адреса
}List_I2C_Modes;

typedef enum
{
I2C_CMD_OK = 1,
I2C_ERR_SMBALERT,
I2C_ERR_TIMEOUT,
I2C_ERR_PEC,
I2C_ERR_OVR,
I2C_ERR_NAK,
I2C_ERR_ARLO,
I2C_ERR_BUS,
I2C_ERR_UNKNOWN, //Неизвестная ошибка, возможно баг библиотеки. Семафор не отдался в течении I2C_TIMEOUT, I2Cx_ER_IRQ не вызвалось.
}List_I2C_Result;

extern List_I2C_Result I2C3Init(void);
extern List_I2C_Result I2C_Master_BufferRead(uint8_t SlaveAddress ,uint8_t* pBuffer ,uint8_t NumByteToRead );
extern List_I2C_Result I2C_Master_BufferWrite(uint8_t SlaveAddress ,uint8_t RegAddress ,uint8_t* pBuffer, uint8_t NumByteToWrite );
extern List_I2C_Result I2C_Master_BufferWriteRead(uint8_t SlaveAddress ,uint32_t RegAddress ,uint8_t* pBuffer, uint8_t NumByteToRead );

extern xSemaphoreHandle I2C3Mutex; //Мьютекс

// Для режима I2C_MODE_WRITEREAD, указываем сколько байт в адресе (байт на запись)
#define WR_1BYTE_ADDR(first_byte) (0x01000000 | (first_byte))
#define WR_2BYTE_ADDR(first_byte, second_byte) (0x02000000 | (((uint32_t)(second_byte) << 8) | (first_byte)))
#define WR_3BYTE_ADDR(first_byte, second_byte,third_byte) (0x03000000 | (((uint32_t)(third_byte) << 16) | ((uint32_t)(second_byte) << 8) | (first_byte)))


#endif


Ну и например чтение с часов DS3231:
Код
I2C_Master_BufferWriteRead(DS3231_ADDRESS    ,WR_1BYTE_ADDR(SEC_ADDR)    ,I2CReadBuffer    , 19);
Сергей Борщ
QUOTE (Volldemar @ Sep 5 2017, 10:23) *
т.е. своеобразный передатчик, а непрерывная выдача необходима для того, что бы небыло так называемой "разрыва фазы",
Когда возился со SPI на F407 обратил внимание, что между посылками присутствуют паузы и ПДП тут никак не помогает. Паузы были даже на низкой скорости. Посмотрите логическим анализатором, возможно на 411 будет то же самое и вам придется искать какой-то другой способ (например - подавать на модулятор сигнал ЦАП, а ЦАП грузить через ПДП по таймеру).
adnega
Цитата(Volldemar @ Sep 5 2017, 11:12) *
в F411 есть интереный момент Double Buffer mode DMA, вот только примеров как это заюзать нет, а у меня не хочет работать sad.gif

Вам нужно DMA_Mode_Circular.
Volldemar
Цитата(adnega @ Sep 5 2017, 11:41) *
Вам нужно DMA_Mode_Circular.

DMA_Mode_Circular у меня работает, но это чисто для отладки Вч части, так как постоянно выдаётся таблица из флеши, а мне нужно готовить данные т.е. модулировать исходные данные процессором для подачи в ВЧ модулятор, где уже будет этот поток модулироваться несущей для излучения в антенну.
adnega
Цитата(Volldemar @ Sep 5 2017, 11:48) *
DMA_Mode_Circular у меня работает, но это чисто для отладки Вч части, так как постоянно выдаётся таблица из флеши, а мне нужно готовить данные т.е. модулировать исходные данные процессором для подачи в ВЧ модулятор, где уже будет этот поток модулироваться несущей для излучения в антенну.

Дык, сделайте обработчик прерываний HT и TC для этого DMA.
Я делаю примерно так
Код
void DMA2_Stream7_IRQHandler(void)
{
    if(DMA2->HISR & (1 << DMA_HISR_HTIF7))
    {
        DMA2->HIFCR = (1 << DMA_HISR_HTIF7);
        dma_event = 1;
    }

    if(DMA2->HISR & (1 << DMA_HISR_TCIF7))
    {
        DMA2->HIFCR = (1 << DMA_HISR_TCIF7);
        dma_event = 2;
    }
}

в idle

if(dma_event == 1)
{
  dma_event = 0;
  // заполняем первую половину кольца
}
if(dma_event == 2)
{
  dma_event = 0;
  // заполняем вторую половину кольца
}
Volldemar
Инит ДМА вот такой:
Код
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_Circular;
      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 = (uint8_t)(configKERNEL_INTERRUPT_PRIORITY >> 4);
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init ( &NVIC_InitStructure );

    SPI_I2S_ITConfig ( SPIx, SPI_I2S_IT_TXE, ENABLE );

    DMA_DoubleBufferModeConfig(DMA2_Stream5, Buffer1TX_SPI1[0], DMA_Memory_0); //первый массив для выдачи
    DMA_DoubleBufferModeConfig(DMA2_Stream5, Buffer2TX_SPI1[0], DMA_Memory_1); //второй массив для выдачи

    DMA_DoubleBufferModeCmd ( DMA2_Stream5, ENABLE );

    SPI_I2S_DMACmd ( SPI_DMA_MASTER, SPI_I2S_DMAReq_Tx, ENABLE );
    DMA_ITConfig ( SPI_DMA_MASTER_Tx_DMA_Stream, DMA_IT_TC, ENABLE );
}

обработчик прерывания:
Код
void DMA2_Stream5_IRQHandler ( void )
{
    portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

  // Stream3 transfer complete interrupt?
  if(DMA_GetITStatus (SPIx_TX_DMA_STREAM,SPI_DMA_MASTER_Tx_DMA_IT))
  {
    // clear pending interrupt
    DMA_ClearITPendingBit (SPIx_TX_DMA_STREAM,SPI_DMA_MASTER_Tx_DMA_IT);

    if(DMA_GetCurrentMemoryTarget (SPIx_TX_DMA_STREAM))
    {
      // Memory 1 is current target
      DMA_MemoryTargetConfig (SPIx_TX_DMA_STREAM,Buffer2TX_SPI1[0],DMA_Memory_0);
    }
    else
    {
      // Memory 0 is current target
      DMA_MemoryTargetConfig(SPIx_TX_DMA_STREAM,Buffer1TX_SPI1[0],DMA_Memory_1);
     }
  }
  xSemaphoreGiveFromISR ( xSemaphore_spi1, &xHigherPriorityTaskWoken );
      xTaskResumeFromISR (&xHandleSPI1);
      portEND_SWITCHING_ISR ( xHigherPriorityTaskWoken );

}

ну а запускается всё вот так:
Код
        ukladkabufTXSPI1 ( Buffer1TX_SPI1 );//заполнение первого массива инфой
        ukladkabufTXSPI1 ( Buffer2TX_SPI1 );//заполнение второго массива инфой
        DMA_Cmd ( SPI_DMA_MASTER_Tx_DMA_Stream, ENABLE );

и всё это Не работает, ЧЯДНТ?
Hold
Как минимум, в функцию DMA_DoubleBufferModeConfig(DMA2_Stream5, Buffer1TX_SPI1[0], DMA_Memory_0); необходимо давать адрес буфера, а него его первое значение. Функция то всё съест, на входе просто uint32_t. Улетает небось в hardFault, т.е. лезете в непонятную область данных.
Volldemar
Цитата(Hold @ Sep 5 2017, 15:18) *
Как минимум, в функцию DMA_DoubleBufferModeConfig(DMA2_Stream5, Buffer1TX_SPI1[0], DMA_Memory_0); необходимо давать адрес буфера, а него его первое значение. Функция то всё съест, на входе просто uint32_t. Улетает небось в hardFault, т.е. лезете в непонятную область данных.

если прописать:
Код
DMA_DoubleBufferModeConfig(DMA2_Stream5, &Buffer1TX_SPI1, DMA_Memory_0);

вываливает варнинг:
Код
warning: passing argument 2 of 'DMA_DoubleBufferModeConfig' makes integer from pointer without a cast [-Wint-conversion]
Сергей Борщ
QUOTE (Volldemar @ Sep 5 2017, 15:20) *
вываливает варнинг:
Посылайте луч поноса авторам этой "библиотеки", которые передают указатель в виде целого (и даже не специально предназначенного для этого типа uintptr_t) и добавляйте явное приведение типа. Кстати, взятие адреса тут не требуется - имя массива автоматически преобразовывается к указателю на его нулевой элемент:
CODE
DMA_DoubleBufferModeConfig(DMA2_Stream5, (uintptr_t)Buffer1TX_SPI1, DMA_Memory_0);

Volldemar
даже если прописать:
Код
DMA_DoubleBufferModeConfig(DMA2_Stream5, Buffer1TX_SPI1, DMA_Memory_0);

что собственно не является ошибкой, получается такой же варнинг:
Код
warning: passing argument 2 of 'DMA_DoubleBufferModeConfig' makes integer from pointer without a cast [-Wint-conversion]

так что только так передавать:
Код
Buffer1TX_SPI1[0]
jcxz
Цитата(Сергей Борщ @ Sep 5 2017, 11:41) *
Когда возился со SPI на F407 обратил внимание, что между посылками присутствуют паузы и ПДП тут никак не помогает. Паузы были даже на низкой скорости.

Если Вы про паузы между словами, то их никак не убрать - в STM насколько помню нет такой возможности. Полклока каждые 8 или 16 бит.
Они вставляются аппаратно контроллером SPI.
Например в XMC4700 их можно убрать.
Сергей Борщ
QUOTE (Volldemar @ Sep 5 2017, 15:35) *
даже если прописать:
CODE
DMA_DoubleBufferModeConfig(DMA2_Stream5, Buffer1TX_SPI1, DMA_Memory_0);

что собственно не является ошибкой, получается такой же варнинг:
CODE
warning: passing argument 2 of 'DMA_DoubleBufferModeConfig' makes integer from pointer without a cast [-Wint-conversion]

Во-первых - да, формально это не является ошибкой, поэтому вы получаете не error, а только лишь warning.
А теперь найдите 10 отличий:
CODE
DMA_DoubleBufferModeConfig(DMA2_Stream5, (uintptr_t)Buffer1TX_SPI1, DMA_Memory_0);


QUOTE (Volldemar @ Sep 5 2017, 15:35) *
так что только так передавать:
CODE
Buffer1TX_SPI1[0]
Если вам все равно, что передавать - то да, можно и так.
Volldemar
Сергей Борщ - спасибо, внял вашему совету!!!
(uintptr_t)Buffer1TX_SPI1 - полечило варнинг sm.gif
Aleksandr Baranov
Цитата(Volldemar @ Sep 5 2017, 08:35) *
так что только так передавать: Buffer1TX_SPI1[0]


Buffer1TX_SPI1[0] - это не указатель. Его нельзя передавать. Можно так, например: &Buffer1TX_SPI1[0] или так Buffer1TX_SPI1
Volldemar
Цитата(Aleksandr Baranov @ Sep 5 2017, 19:39) *
Buffer1TX_SPI1[0] - это не указатель. Его нельзя передавать. Можно так, например: &Buffer1TX_SPI1[0] или так Buffer1TX_SPI1

Вопрос о правильной передаче параметра - решен!
Volldemar
Вроде зашевелилось!!!
Появилась выдача в SPI, но тут подкралось НО! как теперь определять, что мнфа из одного из массивов уже ушла полностью и пора готовить второй массив с данными?
Aleksandr Baranov
Цитата(Volldemar @ Sep 6 2017, 07:43) *
Появилась выдача в SPI, но тут подкралось НО! как теперь определять, что мнфа из одного из массивов уже ушла полностью и пора готовить второй массив с данными?

"Half transfer interrupt" никак не поможет?
jcxz
Цитата(Volldemar @ Sep 6 2017, 14:43) *
Появилась выдача в SPI, но тут подкралось НО! как теперь определять, что мнфа из одного из массивов уже ушла полностью и пора готовить второй массив с данными?

Если вопрос именно о непрерывной передаче, то когда "мнфа из одного из массивов уже ушла полностью", готовить 2-ой уже поздно.
Volldemar
Цитата(jcxz @ Sep 7 2017, 22:36) *
Если вопрос именно о непрерывной передаче, то когда "мнфа из одного из массивов уже ушла полностью", готовить 2-ой уже поздно.

как тогда организовать процесс? если есть мысли, буду благодарен!!!
jcxz
Цитата(Volldemar @ Sep 8 2017, 20:29) *
как тогда организовать процесс? если есть мысли, буду благодарен!!!

Естественно: как только закончилась передача из 1го буфера, надо начинать готовить в нём новые данные (пока идёт передача из 2-го буфера, подготовленного заранее).
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.