|
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
|
|
|
|
|
 |
Ответов
(15 - 29)
|
Sep 4 2017, 12:01
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342

|
[quote] Т.к. Stream автоматически выключается после окончания передачи, что явно указано в ДШ: [attachment=108643:STM32F40...9_439_RM.jpg] Из-за этого незаходит в иф? Код if ( DMA_GetITStatus ( SPI_DMA_MASTER_Tx_DMA_Stream, DMA_IT_TCIF5 ) == SET )
|
|
|
|
|
Sep 4 2017, 12:09
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342

|
Цитата(Сергей Борщ @ Sep 4 2017, 15:02)  Несомненным достижением инженеров ST можно назвать отсутствие прерывания на этот флаг. А разве прерывание: Код SPI_I2S_IT_TXE: Tx buffer empty interrupt mask это не оно? т.е. по опустошению передающего буфера генерится прерывание и сраюатывает этотфлаг
Сообщение отредактировал Volldemar - Sep 4 2017, 12:11
|
|
|
|
|
Sep 5 2017, 04:09
|
Участник

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

|
Цитата(Сергей Борщ @ Sep 4 2017, 19:02)  Несомненным достижением инженеров ST можно назвать отсутствие прерывания на этот флаг. Помню долго недоумевал, как же отслеживать окончание передачи только по Tx, используя прерывания. Была уже мысль включить Rx канал DMA, без физического подключения Rx, и работать по нему. Но руки так и не дошли.
|
|
|
|
|
Sep 5 2017, 06:29
|
Участник

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

|
SPI, по сравнению с I2C, еще относительно безглючный модуль. I2C так и не удалось корректно заставить работать на прерываниях. Точнее он работает, но в какой-то момент, после старт-бита зависает. Обмен у нас редкий, так что перед каждым обменом полностью ресетим модуль. Но это уже оффтоп.
|
|
|
|
|
Sep 5 2017, 06:58
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(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=0PS: Да - и если дело в помехах, то какой смысл в сбросе I2C-модуля перед обменом? Ведь помеха может быть во время транзакции. Это поможет только при багах в ПО. Но тогда это - костыль на кривой код.
|
|
|
|
|
Sep 5 2017, 07:23
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342

|
Ребят, канешна спасибо за инфу, очень пригодится в будущем, но тема про SPI+DMA, точнее double buffer DMA+SPI, задача- необходимо реализовать непрерывный вывод в TX SPI потока данных, которые потом поступают на ВЧ модулятор и ессно потом на антенну, т.е. своеобразный передатчик, а непрерывная выдача необходима для того, что бы небыло так называемой "разрыва фазы", что бы приемник мог принять и демодулировать инфу. Вот помогли бы мне с этим, буду премного благодарен!
Сообщение отредактировал Volldemar - Sep 5 2017, 07:24
|
|
|
|
|
Sep 5 2017, 08:12
|
Частый гость
 
Группа: Участник
Сообщений: 121
Регистрация: 27-04-09
Из: Украина
Пользователь №: 48 342

|
Цитата(adnega @ Sep 5 2017, 10:56)  Значит поток у вас непрерывный. Тут все просто - делаете кольцевой буфер на DMA и забываете вообще про SPI. Готовите в прерываниях DMA HT и TC новую половину данных. SPI лучше сделать 16 бит, если выдаете с частотой не сильно меньше AHB. Я делал на стареньком STM32F103 вывод на VGA-монитор - очень похожая задачка. у меня данные байтовые, т.е. и выдача в SPI байтовая и строго выдержанная тактовая в 1 МГц, но это уже в настройках самого SPI реализовано. в F411 есть интереный момент Double Buffer mode DMA, вот только примеров как это заюзать нет, а у меня не хочет работать
|
|
|
|
|
Sep 5 2017, 08:18
|
Участник

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

|
Цитата(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=0PS: Да - и если дело в помехах, то какой смысл в сбросе 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);
|
|
|
|
|
Sep 5 2017, 08:41
|

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

|
QUOTE (Volldemar @ Sep 5 2017, 10:23)  т.е. своеобразный передатчик, а непрерывная выдача необходима для того, что бы небыло так называемой "разрыва фазы", Когда возился со SPI на F407 обратил внимание, что между посылками присутствуют паузы и ПДП тут никак не помогает. Паузы были даже на низкой скорости. Посмотрите логическим анализатором, возможно на 411 будет то же самое и вам придется искать какой-то другой способ (например - подавать на модулятор сигнал ЦАП, а ЦАП грузить через ПДП по таймеру).
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|