From aae08f710a866121b875b838faa82dc2e627390b Mon Sep 17 00:00:00 2001 From: Alexey Zholtikov Date: Sun, 10 Aug 2025 08:11:55 +0300 Subject: [PATCH] wip: --- include/zh_avr_i2c.h | 78 +------------------- zh_avr_i2c.c | 169 +++++++++++++++++++++---------------------- 2 files changed, 85 insertions(+), 162 deletions(-) diff --git a/include/zh_avr_i2c.h b/include/zh_avr_i2c.h index 4d67085..97ef7e5 100644 --- a/include/zh_avr_i2c.h +++ b/include/zh_avr_i2c.h @@ -35,84 +35,10 @@ extern "C" avr_err_t zh_avr_i2c_master_init(const bool pullup); avr_err_t zh_avr_i2c_master_probe(const uint8_t addr, TickType_t xTicksToWait); - avr_err_t zh_avr_i2c_master_transmit(const uint8_t addr, uint8_t *data, uint8_t size, size_t delay); - avr_err_t zh_avr_i2c_master_receive(const uint8_t addr, uint8_t *data, uint8_t size, size_t delay); + avr_err_t zh_avr_i2c_master_transmit(const uint8_t addr, uint8_t *data, uint8_t size, TickType_t xTicksToWait); + avr_err_t zh_avr_i2c_master_receive(const uint8_t addr, uint8_t *data, uint8_t size, TickType_t xTicksToWait); avr_err_t zh_avr_i2c_master_transmit_receive(const uint8_t addr, uint8_t *write_data, uint8_t write_size, uint8_t *read_data, uint8_t read_size, size_t delay); #ifdef __cplusplus } -#endif - -#ifndef IICULTIMATE_H -#define IICULTIMATE_H - - -// #include -// #include - -#define i2c_PORT PORTC // Порт где сидит нога TWI -#define i2c_DDR DDRC -#define i2c_SCL 0 // Биты соответствующих выводов -#define i2c_SDA 1 - -#define i2c_MasterAddress 0x32 // Адрес на который будем отзываться -#define i2c_i_am_slave 1 // Если мы еще и слейвом работаем то 1. А то не услышит! - -#define i2c_MasterBytesRX 1 // Величина принимающего буфера режима Slave, т.е. сколько байт жрем. -#define i2c_MasterBytesTX 1 // Величина Передающего буфера режима Slave , т.е. сколько байт отдаем за сессию. - -#define i2c_MaxBuffer 3 // Величина буфера Master режима RX-TX. Зависит от того какой длины строки мы будем гонять -#define i2c_MaxPageAddrLgth 2 // Максимальная величина адреса страницы. Обычно адрес страницы это один или два байта. - // Зависит от типа ЕЕПРОМ или другой микросхемы. - -#define i2c_type_msk 0b00001100 // Маска режима -#define i2c_sarp 0b00000000 // Start-Addr_R-Read-Stop Это режим простого чтения. Например из слейва или из епрома с текущего адреса -#define i2c_sawp 0b00000100 // Start-Addr_W-Write-Stop Это режим простой записи. В том числе и запись с адресом страницы. -#define i2c_sawsarp 0b00001000 // Start-Addr_W-WrPageAdr-rStart-Addr_R-Read-Stop Это режим с предварительной записью текущего адреса страницы - -#define i2c_Err_msk 0b00110011 // Маска кода ошибок -#define i2c_Err_NO 0b00000000 // All Right! -- Все окей, передача успешна. -#define i2c_ERR_NA 0b00010000 // Device No Answer -- Слейв не отвечает. Т.к. либо занят, либо его нет на линии. -#define i2c_ERR_LP 0b00100000 // Low Priority -- нас перехватили собственным адресом, либо мы проиграли арбитраж -#define i2c_ERR_NK 0b00000010 // Received NACK. End Transmittion. -- Был получен NACK. Бывает и так. -#define i2c_ERR_BF 0b00000001 // BUS FAIL -- Автобус сломался. И этим все сказано. Можно попробовать сделать переинициализацию шины - -#define i2c_Interrupted 0b10000000 // Transmiting Interrupted Битмаска установки флага занятости -#define i2c_NoInterrupted 0b01111111 // Transmiting No Interrupted Битмаска снятия флага занятости - -#define i2c_Busy 0b01000000 // Trans is Busy Битмаска флага "Передатчик занят, руками не трогать". -#define i2c_Free 0b10111111 // Trans is Free Битмаска снятия флага занятости. - -#define MACRO_i2c_WhatDo_MasterOut (MasterOutFunc)(); // Макросы для режимо выхода. Пока тут функция, но может быть что угодно -#define MACRO_i2c_WhatDo_SlaveOut (SlaveOutFunc)(); -#define MACRO_i2c_WhatDo_ErrorOut (ErrorOutFunc)(); - -typedef void (*IIC_F)(void); // Тип указателя на функцию - -extern IIC_F MasterOutFunc; // Подрбрости в сишнике. -extern IIC_F SlaveOutFunc; -extern IIC_F ErrorOutFunc; - -extern uint8_t i2c_Do; -extern uint8_t i2c_InBuff[i2c_MasterBytesRX]; -extern uint8_t i2c_OutBuff[i2c_MasterBytesTX]; - -extern uint8_t i2c_SlaveIndex; - -extern uint8_t i2c_Buffer[i2c_MaxBuffer]; -extern uint8_t i2c_index; -extern uint8_t i2c_ByteCount; - -extern uint8_t i2c_SlaveAddress; -extern uint8_t i2c_PageAddress[i2c_MaxPageAddrLgth]; - -extern uint8_t i2c_PageAddrIndex; -extern uint8_t i2c_PageAddrCount; - -void Init_i2c(void); -void Init_Slave_i2c(IIC_F Addr); - -extern uint8_t WorkLog[100]; -extern uint8_t WorkIndex; - #endif \ No newline at end of file diff --git a/zh_avr_i2c.c b/zh_avr_i2c.c index 9ac8e45..7a2f9a9 100644 --- a/zh_avr_i2c.c +++ b/zh_avr_i2c.c @@ -17,16 +17,23 @@ typedef enum { - MASTER_TX, - MASTER_RX, - MASTER_TX_RX, - MASTER_PR + MASTER_WRITE, + MASTER_READ, + MASTER_WRITE_REG, + MASTER_READ_REG, + MASTER_PROBE } _work_mode_t; +avr_err_t _zh_avr_i2c_master_start(TickType_t xTicksToWait); + static EventGroupHandle_t _event_group_handle = NULL; static uint8_t _target_i2c_address = 0; volatile static uint8_t _work_mode = 0; +volatile static uint8_t *_master_tx_data = NULL; +volatile static uint8_t _master_tx_data_size = 0; +volatile static uint8_t _master_tx_data_counter = 0; + avr_err_t zh_avr_i2c_master_init(const bool pullup) { _event_group_handle = xEventGroupCreate(); @@ -45,8 +52,39 @@ avr_err_t zh_avr_i2c_master_init(const bool pullup) avr_err_t zh_avr_i2c_master_probe(const uint8_t addr, TickType_t xTicksToWait) { - _work_mode = MASTER_PR; + _work_mode = MASTER_PROBE; _target_i2c_address = addr; + return _zh_avr_i2c_master_start(xTicksToWait); +} + +avr_err_t zh_avr_i2c_master_transmit(const uint8_t addr, uint8_t *data, uint8_t size, TickType_t xTicksToWait) +{ + ZH_ERROR_CHECK(data != NULL || size > 0, AVR_ERR_INVALID_ARG); + _work_mode = MASTER_WRITE; + _target_i2c_address = addr; + _master_tx_data = data; + _master_tx_data_size = size; + _master_tx_data_counter = 0; + return _zh_avr_i2c_master_start(xTicksToWait); +} + +avr_err_t zh_avr_i2c_master_receive(const uint8_t addr, uint8_t *data, uint8_t size, TickType_t xTicksToWait) +{ + ZH_ERROR_CHECK(data != NULL || size > 0, AVR_ERR_INVALID_ARG); + _work_mode = MASTER_READ; + _target_i2c_address = addr; + _master_tx_data_size = size; + _master_tx_data_counter = 0; + return _zh_avr_i2c_master_start(xTicksToWait); +} + +avr_err_t zh_avr_i2c_master_transmit_receive(const uint8_t addr, uint8_t *write_data, uint8_t write_size, uint8_t *read_data, uint8_t read_size, size_t delay) +{ + return AVR_OK; +} + +avr_err_t _zh_avr_i2c_master_start(TickType_t xTicksToWait) +{ TWCR = I2C_START | (1 << TWSTA); EventBits_t bits = xEventGroupWaitBits(_event_group_handle, I2C_OK | I2C_NACK | I2C_COLLISION | I2C_BUS_FAIL, pdTRUE, pdFALSE, xTicksToWait); if ((bits & I2C_OK) != 0) @@ -63,48 +101,7 @@ avr_err_t zh_avr_i2c_master_probe(const uint8_t addr, TickType_t xTicksToWait) } } -avr_err_t zh_avr_i2c_master_transmit(const uint8_t addr, uint8_t *data, uint8_t size, size_t delay) -{ - TWCR = (1 << TWINT) | (0 << TWEA) | (1 << TWSTA) | (0 << TWSTO) | (0 << TWWC) | (1 << TWEN) | (1 << TWIE); - return AVR_OK; -} - -avr_err_t zh_avr_i2c_master_receive(const uint8_t addr, uint8_t *data, uint8_t size, size_t delay) -{ - return AVR_OK; -} - -avr_err_t zh_avr_i2c_master_transmit_receive(const uint8_t addr, uint8_t *write_data, uint8_t write_size, uint8_t *read_data, uint8_t read_size, size_t delay) -{ - return AVR_OK; -} - -void DoNothing(void); - -uint8_t i2c_Do; // Переменная состояния передатчика IIC -uint8_t i2c_InBuff[i2c_MasterBytesRX]; // Буфер прием при работе как Slave -uint8_t i2c_OutBuff[i2c_MasterBytesTX]; // Буфер передачи при работе как Slave -uint8_t i2c_SlaveIndex; // Индекс буфера Slave - -uint8_t i2c_Buffer[i2c_MaxBuffer]; // Буфер для данных работы в режиме Master -uint8_t i2c_index; // Индекс этого буфера -uint8_t i2c_ByteCount; // Число байт передаваемых - -uint8_t i2c_SlaveAddress; // Адрес подчиненного - -uint8_t i2c_PageAddress[i2c_MaxPageAddrLgth]; // Буфер адреса страниц (для режима с sawsarp) -uint8_t i2c_PageAddrIndex; // Индекс буфера адреса страниц -uint8_t i2c_PageAddrCount; // Число байт в адресе страницы для текущего Slave - -// Указатели выхода из автомата: -IIC_F MasterOutFunc = &DoNothing; // в Master режиме -IIC_F SlaveOutFunc = &DoNothing; // в режиме Slave -IIC_F ErrorOutFunc = &DoNothing; // в результате ошибки в режиме Master - -uint8_t WorkLog[100]; // Лог пишем сюда -uint8_t WorkIndex = 0; // Индекс лога - -ISR(TWI_vect) // Прерывание TWI Тут наше все. +ISR(TWI_vect) { BaseType_t xHigherPriorityTaskWoken = pdFALSE; switch (TWSR & 0xF8) // Отсекаем биты прескалера @@ -118,35 +115,60 @@ ISR(TWI_vect) // Прерывание TWI Тут наше все. printf("08\n"); switch (_work_mode) { - case MASTER_TX: + case MASTER_WRITE: + TWDR = (_target_i2c_address << 1) | I2C_MASTER_WRITE; + // TWCR = I2C_START; break; - case MASTER_RX: - break; - case MASTER_TX_RX: - break; - case MASTER_PR: + case MASTER_READ: TWDR = (_target_i2c_address << 1) | I2C_MASTER_READ; - TWCR = I2C_START; + // TWCR = I2C_START; + break; + case MASTER_WRITE_REG: + break; + case MASTER_READ_REG: + break; + case MASTER_PROBE: + TWDR = (_target_i2c_address << 1) | I2C_MASTER_READ; + // TWCR = I2C_START; break; default: break; } + TWCR = I2C_START; break; case 0x10: // A repeated START condition has been transmitted. printf("10\n"); - TWCR = I2C_START | (1 << TWSTO); + // TWCR = I2C_START | (1 << TWSTO); break; case 0x18: // SLA+W has been transmitted. ACK has been received. printf("18\n"); + TWDR = *(_master_tx_data++); + _master_tx_data_counter++; + TWCR = I2C_START; break; case 0x20: // SLA+W has been transmitted. NOT ACK has been received. printf("20\n"); + TWCR = I2C_START | (1 << TWSTO); + xEventGroupSetBitsFromISR(_event_group_handle, I2C_NACK, &xHigherPriorityTaskWoken); break; case 0x28: // Data byte has been transmitted. ACK has been received. printf("28\n"); + if (_master_tx_data_counter < _master_tx_data_size) + { + TWDR = *(_master_tx_data++); + _master_tx_data_counter++; + TWCR = I2C_START; + } + else + { + TWCR = I2C_START | (1 << TWSTO); + xEventGroupSetBitsFromISR(_event_group_handle, I2C_OK, &xHigherPriorityTaskWoken); + } break; case 0x30: // Data byte has been transmitted. NOT ACK has been received. printf("30\n"); + TWCR = I2C_START | (1 << TWSTO); + xEventGroupSetBitsFromISR(_event_group_handle, I2C_NACK, &xHigherPriorityTaskWoken); break; case 0x38: // Arbitration lost in SLA+W or data bytes. Arbitration lost in SLA+R or NOT ACK bit. printf("38\n"); @@ -157,13 +179,15 @@ ISR(TWI_vect) // Прерывание TWI Тут наше все. printf("40\n"); switch (_work_mode) { - case MASTER_TX: + case MASTER_WRITE: break; - case MASTER_RX: + case MASTER_READ: break; - case MASTER_TX_RX: + case MASTER_WRITE_REG: break; - case MASTER_PR: + case MASTER_READ_REG: + break; + case MASTER_PROBE: TWCR = I2C_START | (1 << TWSTO); xEventGroupSetBitsFromISR(_event_group_handle, I2C_OK, &xHigherPriorityTaskWoken); break; @@ -675,31 +699,4 @@ ISR(TWI_vect) // Прерывание TWI Тут наше все. { portYIELD(); }; -} - -void DoNothing(void) // Функция пустышка, затыкать несуществующие ссылки -{ -} - -// void Init_i2c(void) // Настройка режима мастера -// { -// i2c_PORT |= 1 << i2c_SCL | 1 << i2c_SDA; // Включим подтяжку на ноги, вдруг юзер на резисторы пожмотился -// i2c_DDR &= ~(1 << i2c_SCL | 1 << i2c_SDA); - -// TWBR = 0x80; // Настроим битрейт -// TWSR = 0x00; -// } - -void Init_Slave_i2c(IIC_F Addr) // Настройка режима слейва (если нужно) -{ - TWAR = i2c_MasterAddress; // Внесем в регистр свой адрес, на который будем отзываться. - // 1 в нулевом бите означает, что мы отзываемся на широковещательные пакеты - SlaveOutFunc = Addr; // Присвоим указателю выхода по слейву функцию выхода - - TWCR = 0 << TWSTA | - 0 << TWSTO | - 0 << TWINT | - 1 << TWEA | - 1 << TWEN | - 1 << TWIE; // Включаем агрегат и начинаем слушать шину. } \ No newline at end of file