ur5cuj 0 4 сентября, 2017 Опубликовано 4 сентября, 2017 · Жалоба Т.к. Stream автоматически выключается после окончания передачи, что явно указано в ДШ: Из-за этого незаходит в иф? if ( DMA_GetITStatus ( SPI_DMA_MASTER_Tx_DMA_Stream, DMA_IT_TCIF5 ) == SET ) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 4 сентября, 2017 Опубликовано 4 сентября, 2017 · Жалоба Для однозначного отслеживания окончания передачи следует дожидаться флага SPI_SR_BSY в статусном регистре SPI.Несомненным достижением инженеров ST можно назвать отсутствие прерывания на этот флаг. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ur5cuj 0 4 сентября, 2017 Опубликовано 4 сентября, 2017 (изменено) · Жалоба Несомненным достижением инженеров ST можно назвать отсутствие прерывания на этот флаг. А разве прерывание: SPI_I2S_IT_TXE: Tx buffer empty interrupt mask это не оно? т.е. по опустошению передающего буфера генерится прерывание и сраюатывает этотфлаг Изменено 4 сентября, 2017 пользователем Volldemar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 235 4 сентября, 2017 Опубликовано 4 сентября, 2017 · Жалоба это не оно? т.е. по опустошению передающего буфера генерится прерывание и сраюатывает этотфлаг Не оно. Пустой буфер != окончание передачи. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Hold 0 5 сентября, 2017 Опубликовано 5 сентября, 2017 · Жалоба Несомненным достижением инженеров ST можно назвать отсутствие прерывания на этот флаг. Помню долго недоумевал, как же отслеживать окончание передачи только по Tx, используя прерывания. Была уже мысль включить Rx канал DMA, без физического подключения Rx, и работать по нему. Но руки так и не дошли. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 5 сентября, 2017 Опубликовано 5 сентября, 2017 · Жалоба Была уже мысль включить Rx канал DMA, без физического подключения Rx, и работать по нему.Так и приходится. Попутно посылая лучи поноса авторам этого периферийного модуля. В I2C им тоже что-то подобное удалось. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Hold 0 5 сентября, 2017 Опубликовано 5 сентября, 2017 · Жалоба SPI, по сравнению с I2C, еще относительно безглючный модуль. I2C так и не удалось корректно заставить работать на прерываниях. Точнее он работает, но в какой-то момент, после старт-бита зависает. Обмен у нас редкий, так что перед каждым обменом полностью ресетим модуль. Но это уже оффтоп. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 5 сентября, 2017 Опубликовано 5 сентября, 2017 · Жалоба какой-то момент, после старт-бита зависает В результате помехи устройство может недосчитаться CLK и давить линию SDA своим ACK. Перед формированием условия START нужно убедиться, что SDA в 1, иначе подергать CLK. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 235 5 сентября, 2017 Опубликовано 5 сентября, 2017 · Жалоба 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-модуля перед обменом? Ведь помеха может быть во время транзакции. Это поможет только при багах в ПО. Но тогда это - костыль на кривой код. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ur5cuj 0 5 сентября, 2017 Опубликовано 5 сентября, 2017 (изменено) · Жалоба Ребят, канешна спасибо за инфу, очень пригодится в будущем, но тема про SPI+DMA, точнее double buffer DMA+SPI, задача- необходимо реализовать непрерывный вывод в TX SPI потока данных, которые потом поступают на ВЧ модулятор и ессно потом на антенну, т.е. своеобразный передатчик, а непрерывная выдача необходима для того, что бы небыло так называемой "разрыва фазы", что бы приемник мог принять и демодулировать инфу. Вот помогли бы мне с этим, буду премного благодарен! Изменено 5 сентября, 2017 пользователем Volldemar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 5 сентября, 2017 Опубликовано 5 сентября, 2017 · Жалоба Вот помогли бы мне с этим, буду премного благодарен! Значит поток у вас непрерывный. Тут все просто - делаете кольцевой буфер на DMA и забываете вообще про SPI. Готовите в прерываниях DMA HT и TC новую половину данных. SPI лучше сделать 16 бит, если выдаете с частотой не сильно меньше AHB. Я делал на стареньком STM32F103 вывод на VGA-монитор - очень похожая задачка. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ur5cuj 0 5 сентября, 2017 Опубликовано 5 сентября, 2017 · Жалоба Значит поток у вас непрерывный. Тут все просто - делаете кольцевой буфер на DMA и забываете вообще про SPI. Готовите в прерываниях DMA HT и TC новую половину данных. SPI лучше сделать 16 бит, если выдаете с частотой не сильно меньше AHB. Я делал на стареньком STM32F103 вывод на VGA-монитор - очень похожая задачка. у меня данные байтовые, т.е. и выдача в SPI байтовая и строго выдержанная тактовая в 1 МГц, но это уже в настройках самого SPI реализовано. в F411 есть интереный момент Double Buffer mode DMA, вот только примеров как это заюзать нет, а у меня не хочет работать :( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Hold 0 5 сентября, 2017 Опубликовано 5 сентября, 2017 · Жалоба При отсутствии помех? У меня устройство на 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); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 134 5 сентября, 2017 Опубликовано 5 сентября, 2017 · Жалоба т.е. своеобразный передатчик, а непрерывная выдача необходима для того, что бы небыло так называемой "разрыва фазы",Когда возился со SPI на F407 обратил внимание, что между посылками присутствуют паузы и ПДП тут никак не помогает. Паузы были даже на низкой скорости. Посмотрите логическим анализатором, возможно на 411 будет то же самое и вам придется искать какой-то другой способ (например - подавать на модулятор сигнал ЦАП, а ЦАП грузить через ПДП по таймеру). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 5 сентября, 2017 Опубликовано 5 сентября, 2017 · Жалоба в F411 есть интереный момент Double Buffer mode DMA, вот только примеров как это заюзать нет, а у меня не хочет работать :( Вам нужно DMA_Mode_Circular. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться