Перейти к содержанию
    

Т.к. Stream автоматически выключается после окончания передачи, что явно указано в ДШ:

post-95184-1504521284_thumb.jpg

Из-за этого незаходит в иф?

if ( DMA_GetITStatus ( SPI_DMA_MASTER_Tx_DMA_Stream, DMA_IT_TCIF5 ) == SET )

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Для однозначного отслеживания окончания передачи следует дожидаться флага SPI_SR_BSY в статусном регистре SPI.
Несомненным достижением инженеров ST можно назвать отсутствие прерывания на этот флаг.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Несомненным достижением инженеров ST можно назвать отсутствие прерывания на этот флаг.

А разве прерывание:

SPI_I2S_IT_TXE: Tx buffer empty interrupt mask

это не оно? т.е. по опустошению передающего буфера генерится прерывание и сраюатывает этотфлаг

Изменено пользователем Volldemar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

это не оно? т.е. по опустошению передающего буфера генерится прерывание и сраюатывает этотфлаг

Не оно. Пустой буфер != окончание передачи.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Несомненным достижением инженеров ST можно назвать отсутствие прерывания на этот флаг.

Помню долго недоумевал, как же отслеживать окончание передачи только по Tx, используя прерывания. Была уже мысль включить Rx канал DMA, без физического подключения Rx, и работать по нему. Но руки так и не дошли.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Была уже мысль включить Rx канал DMA, без физического подключения Rx, и работать по нему.
Так и приходится. Попутно посылая лучи поноса авторам этого периферийного модуля. В I2C им тоже что-то подобное удалось.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

SPI, по сравнению с I2C, еще относительно безглючный модуль. I2C так и не удалось корректно заставить работать на прерываниях. Точнее он работает, но в какой-то момент, после старт-бита зависает. Обмен у нас редкий, так что перед каждым обменом полностью ресетим модуль. Но это уже оффтоп.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

какой-то момент, после старт-бита зависает

В результате помехи устройство может недосчитаться CLK и давить линию SDA своим ACK.

Перед формированием условия START нужно убедиться, что SDA в 1, иначе подергать CLK.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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-модуля перед обменом? Ведь помеха может быть во время транзакции. Это поможет только при багах в ПО. Но тогда это - костыль на кривой код.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Изменено пользователем Volldemar

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот помогли бы мне с этим, буду премного благодарен!

Значит поток у вас непрерывный. Тут все просто - делаете кольцевой буфер на DMA и забываете вообще про SPI.

Готовите в прерываниях DMA HT и TC новую половину данных. SPI лучше сделать 16 бит, если выдаете с частотой

не сильно меньше AHB. Я делал на стареньком STM32F103 вывод на VGA-монитор - очень похожая задачка.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Значит поток у вас непрерывный. Тут все просто - делаете кольцевой буфер на DMA и забываете вообще про SPI.

Готовите в прерываниях DMA HT и TC новую половину данных. SPI лучше сделать 16 бит, если выдаете с частотой

не сильно меньше AHB. Я делал на стареньком STM32F103 вывод на VGA-монитор - очень похожая задачка.

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

 

в F411 есть интереный момент Double Buffer mode DMA, вот только примеров как это заюзать нет, а у меня не хочет работать :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

При отсутствии помех?

У меня устройство на 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 мм, рядом силовухи нет.

#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();
}

#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);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

т.е. своеобразный передатчик, а непрерывная выдача необходима для того, что бы небыло так называемой "разрыва фазы",
Когда возился со SPI на F407 обратил внимание, что между посылками присутствуют паузы и ПДП тут никак не помогает. Паузы были даже на низкой скорости. Посмотрите логическим анализатором, возможно на 411 будет то же самое и вам придется искать какой-то другой способ (например - подавать на модулятор сигнал ЦАП, а ЦАП грузить через ПДП по таймеру).

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

в F411 есть интереный момент Double Buffer mode DMA, вот только примеров как это заюзать нет, а у меня не хочет работать :(

Вам нужно DMA_Mode_Circular.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...