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

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


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

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

Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 4 2017, 12:02
Сообщение #17


Гуру
******

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



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


--------------------
На любой вопрос даю любой ответ
"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
Volldemar
сообщение Sep 4 2017, 12:09
Сообщение #18


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

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


Гуру
******

Группа: Свой
Сообщений: 3 639
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



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

Не оно. Пустой буфер != окончание передачи.
Go to the top of the page
 
+Quote Post
Hold
сообщение Sep 5 2017, 04:09
Сообщение #20


Участник
*

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



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

Помню долго недоумевал, как же отслеживать окончание передачи только по Tx, используя прерывания. Была уже мысль включить Rx канал DMA, без физического подключения Rx, и работать по нему. Но руки так и не дошли.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 5 2017, 06:13
Сообщение #21


Гуру
******

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



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


--------------------
На любой вопрос даю любой ответ
"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
Hold
сообщение Sep 5 2017, 06:29
Сообщение #22


Участник
*

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



SPI, по сравнению с I2C, еще относительно безглючный модуль. I2C так и не удалось корректно заставить работать на прерываниях. Точнее он работает, но в какой-то момент, после старт-бита зависает. Обмен у нас редкий, так что перед каждым обменом полностью ресетим модуль. Но это уже оффтоп.
Go to the top of the page
 
+Quote Post
adnega
сообщение Sep 5 2017, 06:37
Сообщение #23


Гуру
******

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



Цитата(Hold @ Sep 5 2017, 09:29) *
какой-то момент, после старт-бита зависает

В результате помехи устройство может недосчитаться CLK и давить линию SDA своим ACK.
Перед формированием условия START нужно убедиться, что SDA в 1, иначе подергать CLK.
Go to the top of the page
 
+Quote Post
jcxz
сообщение Sep 5 2017, 06:58
Сообщение #24


Гуру
******

Группа: Свой
Сообщений: 3 639
Регистрация: 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=0

PS: Да - и если дело в помехах, то какой смысл в сбросе I2C-модуля перед обменом? Ведь помеха может быть во время транзакции. Это поможет только при багах в ПО. Но тогда это - костыль на кривой код.
Go to the top of the page
 
+Quote Post
Volldemar
сообщение Sep 5 2017, 07:23
Сообщение #25


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

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



Ребят, канешна спасибо за инфу, очень пригодится в будущем, но тема про SPI+DMA, точнее double buffer DMA+SPI, задача- необходимо реализовать непрерывный вывод в TX SPI потока данных, которые потом поступают на ВЧ модулятор и ессно потом на антенну, т.е. своеобразный передатчик, а непрерывная выдача необходима для того, что бы небыло так называемой "разрыва фазы", что бы приемник мог принять и демодулировать инфу. Вот помогли бы мне с этим, буду премного благодарен!

Сообщение отредактировал Volldemar - Sep 5 2017, 07:24
Go to the top of the page
 
+Quote Post
adnega
сообщение Sep 5 2017, 07:56
Сообщение #26


Гуру
******

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



Цитата(Volldemar @ Sep 5 2017, 10:23) *
Вот помогли бы мне с этим, буду премного благодарен!

Значит поток у вас непрерывный. Тут все просто - делаете кольцевой буфер на DMA и забываете вообще про SPI.
Готовите в прерываниях DMA HT и TC новую половину данных. SPI лучше сделать 16 бит, если выдаете с частотой
не сильно меньше AHB. Я делал на стареньком STM32F103 вывод на VGA-монитор - очень похожая задачка.
Go to the top of the page
 
+Quote Post
Volldemar
сообщение Sep 5 2017, 08:12
Сообщение #27


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

Группа: Участник
Сообщений: 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, вот только примеров как это заюзать нет, а у меня не хочет работать sad.gif
Go to the top of the page
 
+Quote Post
Hold
сообщение Sep 5 2017, 08:18
Сообщение #28


Участник
*

Группа: Участник
Сообщений: 21
Регистрация: 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=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);
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 5 2017, 08:41
Сообщение #29


Гуру
******

Группа: Модераторы
Сообщений: 8 035
Регистрация: 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)
Go to the top of the page
 
+Quote Post
adnega
сообщение Sep 5 2017, 08:41
Сообщение #30


Гуру
******

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



Цитата(Volldemar @ Sep 5 2017, 11:12) *
в F411 есть интереный момент Double Buffer mode DMA, вот только примеров как это заюзать нет, а у меня не хочет работать sad.gif

Вам нужно DMA_Mode_Circular.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 20th September 2017 - 16:41
Рейтинг@Mail.ru


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