Search the Community
Showing results for tags 'I2C STM32'.
-
Есть плата, на которой находятся MCP348 и STM32F103T8U6. К MCP подключается термопара, стмка должна собирать преобразованные данные с MCP через интерфейс I2C и обрабатывать данные. Я застрял на моменте сбора данных. Написал функции для общения стм и mcp, но в ответ получаю это: При этом не важно какой канал выбран и к какому каналу подключена термопара. Функция main: int main(void) { Configure_GPIO_LED(); Configure_GPIO_I2C1(); Configure_I2C1_Master(); Configure_SysTick(); reg_conf = CONFIG_REG(1, 3, 1, 0, 0); while (1) { I2C_write_MCP(DA3_1_ADDR, reg_conf); delay(50); I2C_read_MCP(DA3_1_ADDR); delay(50); } } Функция чтения: void I2C_read_MCP(uint8_t slave_addr) { I2C1->CR1 |= I2C_CR1_START; while(!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = (uint8_t)(DEVICE_CODE | (slave_addr << 1) | MODE_READ); while(!(I2C1->SR1 & I2C_SR1_ADDR)); for(int i = 0; i < 3; i++) { while(!(I2C1->SR1 & I2C_SR1_RXNE)); output[i] = I2C1->DR; } I2C1->CR1 |= I2C_CR1_STOP; } Функция записи: void I2C_write_MCP(uint8_t slave_addr, uint8_t data) { I2C1->CR1 |= I2C_CR1_START; while(!(I2C1->SR1 & I2C_SR1_SB)); I2C1->DR = (uint8_t)(DEVICE_CODE | (slave_addr << 1) | MODE_WRITE); while(!(I2C1->SR1 & I2C_SR1_TXE)); delay(1); I2C1->DR = data; while(!(I2C1->SR1 & I2C_SR1_TXE)); I2C1->CR1 |= I2C_CR1_STOP; } Функция настройки модуля I2C: void Configure_I2C1_Master(void) { RCC->APB1ENR |= RCC_APB1ENR_I2C1EN; I2C1->CR1 &= ~I2C_CR1_SMBUS; I2C1->CR2 |= 48; I2C1->CCR &= ~I2C_CCR_CCR; I2C1->CCR |= 120; I2C1->CCR |= I2C_CCR_FS; I2C1->TRISE = 24; I2C1->CR1 |= I2C_CR1_PE; } Подскажите, в чем может быть проблема? Или что я делаю не так.
-
Здравствуйте. Нужно разобраться с принципом работы интерфейса I2C на Stm32. понимаю, что материала в интернете много, но почему-то даже просто структура, где определяются параметры, у меня другая. Моя вот такая: typedef struct { uint32_t I2C_Timing; uint32_t I2C_AnalogFilter; uint32_t I2C_DigitalFilter; uint32_t I2C_Mode; uint32_t I2C_OwnAddress1; uint32_t I2C_Ack; uint32_t I2C_AcknowledgedAddress; }I2C_InitTypeDef; Те, что даются в примерах, в статьях, такая: typedef struct { uint32_t I2C_ClockSpeed; uint16_t I2C_Mode; uint16_t I2C_DutyCycle; uint16_t I2C_OwnAddress1; uint16_t I2C_Ack; uint16_t I2C_AcknowledgedAddress; }I2C_InitTypeDef; Найдя пример на этом форуме (https://forum.cxem.net/index.php?/topic/202586-i2c-%D0%B2-stm32f030/) увидел, что используются параметры такие же, что и у меня, но теперь не понятно, откуда такие значения берут и по какой логике. Прошу не пинать ногами и кидать в меня гнилые помидоры, а помочь разобраться в этом всём или подсказать, где можно найти исчерпывающую информацию, где хорошо и по полочкам всё разложено. Программирую в keil uVision v5 Отладочная плата stm32f0 disco МК stm32f0030r8 Благодарю заранее.
-
В общем понадобилось тут подвесить FRAM к STM32, а пины аппаратных I2C были уже заняты, ну решил не менять пины, а добавить себе на вооружение на всякий, программный I2C. То что удалось нагуглить либо работало криво, либо приходилось допиливать и допиливать. Ну и написал свой с блекджеком и ш.. Так как в сети примеров мало программного I2C на STM32 то решил поделиться. Вдруг кому пригодится. Работает с библиотекой HAL, поправить нужно только под свой камень и свои порты и все работает. I2C.h #ifndef __I2C_H_H__ #define __I2C_H_H__ // G1KuL1N // ПОДКЛЮЧИТЬ БИБЛИОТЕКУ СВОЕГО КОНТРОЛЛЕРА #include "stm32f4xx_hal.h" // В CUBE MX порты I2C настроить на выход (либо в main.c вручну подать тактирование на нужны GPIO) //---подключение шины к пинам----------------------------------------------------- #define SCL_I HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15); #define SDA_I HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_14); #define SCL_O HAL_GPIO_WritePin(GPIOC, GPIO_PIN_15, GPIO_PIN_RESET); #define SDA_O HAL_GPIO_WritePin(GPIOC, GPIO_PIN_14, GPIO_PIN_RESET); //-------------------------------------------------------------------------------- void i2c_init (void); // Инициализация шины void i2c_start_cond (void); // Генерация условия старт void i2c_restart_cond (void); // Генерация условия рестарт void i2c_stop_cond (void) ; // Генерация условия стоп uint8_t i2c_send_byte (uint8_t data) ; //Передать байт (вх. аргумент передаваемый байт) (возвращает 0 - АСК, 1 - NACK) uint8_t i2c_get_byte (uint8_t last_byte) ; //Принять байт (если последний байт то входной аргумент = 1, если будем считывать еще то 0)(возвращает принятый байт) //-------------------------------------------------------------------------------- // ПРИМЕР ИСПОЛЬЗОВАНИЯ //========================================================================================= // Запись uint16_t во внешнюю еепром (FRAM FM24CL64) или любой другой 24LC памяти, // две ячейки, указывается адрес первой ячейки, следующая идет adr++ //========================================================================================= // //void FRAM_W_INT(uint16_t adr, uint16_t dat){ //i2c_start_cond (); //i2c_send_byte (0xA2); //адрес чипа + что будем делать (записывать) //i2c_send_byte ((adr & 0xFF00) >> 8); //i2c_send_byte (adr & 0x00FF); //i2c_send_byte ((dat & 0xFF00) >> 8); //i2c_send_byte (dat & 0x00FF); //i2c_stop_cond(); //} //========================================================================================= // Считывание uint16_t из внешней еепром (FRAM FM24CL64) или любой другой 24LC памяти, // две ячейки, указывается адрес первой ячейки, следующая идет adr++ //========================================================================================= //uint16_t FRAM_R_INT(uint16_t adr){ //uint16_t dat; //i2c_start_cond (); //i2c_send_byte (0xA2); //i2c_send_byte ((adr & 0xFF00) >> 8); //i2c_send_byte (adr & 0x00FF); //i2c_restart_cond (); //i2c_send_byte (0xA3); //dat = i2c_get_byte(0); //dat <<= 8; //dat |= i2c_get_byte(1); //i2c_stop_cond(); //return dat; //} // G1KuL1N #endif /* __I2C_H_H__ */ i2C.c #include "I2C.h" volatile uint8_t i2c_frame_error=0; //----------------------------------------------------------- __STATIC_INLINE void Delay_us (uint32_t __IO us) //Функция задержки в микросекундах us { us *=(SystemCoreClock/1000000)/5; while(us--); } //---------------------------------------------------- void SCL_in (void) //функция отпускания SCL в 1, порт на вход (необходимо установить используемый порт) { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pin = GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); } //---------------------------------------------------- void SCL_out (void) //функция притягивания SCL в 0 (необходимо установить используемый порт) { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pin = GPIO_PIN_15; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); SCL_O; } //---------------------------------------------------- void SDA_in (void) //функция отпускания SDA в 1, порт на вход (необходимо установить используемый порт) { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pin = GPIO_PIN_14; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); } //---------------------------------------------------- void SDA_out (void) //функция притягивания SDA в 0 (необходимо установить используемый порт) { GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.Pin = GPIO_PIN_14; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); SDA_O } //---------------------------------------------------- void i2c_stop_cond (void) // функция генерации условия стоп { uint16_t SCL, SDA; SCL_out(); // притянуть SCL (лог.0) Delay_us(10); SDA_out(); // притянуть SDA (лог.0) Delay_us(10); SCL_in(); // отпустить SCL (лог.1) Delay_us(10); SDA_in(); // отпустить SDA (лог.1) Delay_us(10); // проверка фрейм-ошибки i2c_frame_error=0; // сброс счётчика фрейм-ошибок SCL=SCL_I; SDA=SDA_I; if (SCL == 0) i2c_frame_error++; // проберяем, чтобы на ноге SDA была лог.1, иначе выдаём ошибку фрейма if (SDA == 0) i2c_frame_error++; // проберяем, чтобы на ноге SCL была лог.1, иначе выдаём ошибку фрейма Delay_us(40); } void i2c_init (void) // функция инициализации шины { i2c_stop_cond(); // стоп шины i2c_stop_cond(); // стоп шины } //---------------------------------------------------- void i2c_start_cond (void) // функция генерации условия старт { SDA_out(); // притянуть SDA (лог.0) Delay_us(10); SCL_out(); // притянуть SCL (лог.0) Delay_us(10); } //---------------------------------------------------- void i2c_restart_cond (void) // функция генерации условия рестарт { SDA_in(); // отпустить SDA (лог.1) Delay_us(10); SCL_in(); // отпустить SCL (лог.1) Delay_us(10); SDA_out(); // притянуть SDA (лог.0) Delay_us(10); SCL_out(); // притянуть SCL (лог.0) Delay_us(10); } //---------------------------------------------------- uint8_t i2c_send_byte (uint8_t data) // функция отправки байта { uint8_t i; uint8_t ack=1; //АСК, если АСК=1 – произошла ошибка uint16_t SDA; for (i=0;i<8;i++) { if (data & 0x80) { SDA_in(); // лог.1 } else { SDA_out(); // Выставить бит на SDA (лог.0 } Delay_us(10); SCL_in(); // Записать его импульсом на SCL // отпустить SCL (лог.1) Delay_us(10); SCL_out(); // притянуть SCL (лог.0) data<<=1; // сдвигаем на 1 бит влево } SDA_in(); // отпустить SDA (лог.1), чтобы ведомое устройство смогло сгенерировать ACK Delay_us(10); SCL_in(); // отпустить SCL (лог.1), чтобы ведомое устройство передало ACK Delay_us(10); SDA=SDA_I; if (SDA==0x00) ack=1; else ack=0; // Считать ACK SCL_out(); // притянуть SCL (лог.0) // приём ACK завершён return ack; // вернуть ACK (0) или NACK (1) } //---------------------------------------------------- uint8_t i2c_get_byte (uint8_t last_byte) // функция принятия байта { uint8_t i, res=0; uint16_t SDA; SDA_in(); // отпустить SDA (лог.1) for (i=0;i<8;i++) { res<<=1; SCL_in(); // отпустить SCL (лог.1) //Импульс на SCL Delay_us(10); SDA_in(); SDA=SDA_I; if (SDA==1) res=res|0x01; // Чтение SDA в переменную Если SDA=1 то записываем 1 SCL_out(); // притянуть SCL (лог.0) Delay_us(10); } if (last_byte==0){ SDA_out();} // притянуть SDA (лог.0) // Подтверждение, ACK, будем считывать ещё один байт else {SDA_in();} // отпустить SDA (лог.1) // Без подтверждения, NACK, это последний считанный байт Delay_us(10); SCL_in(); // отпустить SCL (лог.1) Delay_us(10); SCL_out(); // притянуть SCL (лог.0) Delay_us(10); SDA_in(); // отпустить SDA (лог.1) return res; // вернуть считанное значение }
- 16 replies
-
3