Search the Community
Showing results for tags 'Программный I2C'.
-
В общем понадобилось тут подвесить 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
-
Здравствуйте! Имею в наличии 7-ми дюймовый экран от портативного DVD плеера. На фото ресивер на процессоре (чипе) mx88v462. В поисках в интернете для Arduino готовых библиотек не нашел. Но натолкнулся на странички на форуме, http://radiokot.ru/f...068630#p2068630 http://radiokot.ru/f...p?f=61&t=105858 Изначально не мог даже перенести библиотеки из Avr Studio в Arduino. На форуме, добрый человек помог, за что ему большое спасибо.. http://forum.amperka...иблиотеки.6538/ Код для Arduino: //не правильно работает mx88v462_2.zip Код для Avr Studio: //работает на Atmega16 MX88V462.zip Разница между проектами в том что разделен файл на *.cpp и *.h Но на Arduino код не работает, а точнее не совсем правильно, дисплей не инициализируется... Код для Avr точно рабочий, так как создал проект в Avr Studio для Atmega16, скомпилировал, получил hex файл, залил той же ArduinoЙ. MX88V462.zip И результат: Но проблема, перенесенная библиотека для Arduino не работает, дисплей не инициализируеться... Ресивер для дисплей работает по протоколу I2C. В проекте в Avr Studio реализован программный I2C, что и написано на форуме автора данной библиотеки. http://radiokot.ru/f...068630#p2068630 http://radiokot.ru/f...p?f=61&t=105858 В проекте для Arduino было опробовано и программный I2C и при помощи Wire. Но дисплей не инициализируется.. Потом в Proteus подключил Atmega328 и Atmega16. В Atmega328 залил hex файл скомпилированным в Aruino IDE // тот что не правильно работает В Atmega16 залил hex файл, тот с которым инициализировался дисплей и вывел текст. Подключил осциллограф к SDA SCL обеих микроконтроллеров. Chanel A - желтый -> SDA Atmega328 Chanel B - синий -> SCL Atmega328 Chanel C - красный -> SDA Atmega16 Chanel D - зеленый -> SCL Atmega16 И проблема в том, что сигналы не совпадают, скважность и сам сигнал. Частота кварцов выставлена одинаковая, 16M Видно что сам сигнал и скважность разная, думаю из за этого дисплей не инициализируется. При том что код почти одинаковый.. Пожалуйста, помогите решить данный вопрос, очень надо поднять данный дисплей... Буду очень благодарен.
-
- MX88V462
- Перенос библиотеки
-
(and 7 more)
Tagged with: