diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e43b0f9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.DS_Store diff --git a/README.md b/README.md index 898bdbe..96a63bb 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ # zh_avr_i2c -AVR library for I2C bus. \ No newline at end of file +AVR library for I2C bus. diff --git a/include/zh_avr_i2c.h b/include/zh_avr_i2c.h index 128cf35..4f28fb6 100644 --- a/include/zh_avr_i2c.h +++ b/include/zh_avr_i2c.h @@ -1,9 +1,14 @@ #pragma once +#include "FreeRTOS.h" +#include "event_groups.h" +#include "avr/io.h" +#include "avr/interrupt.h" #include "stdlib.h" #include "stdint.h" #include "string.h" #include "stdbool.h" +#include "stdio.h" #ifdef __cplusplus extern "C" @@ -29,6 +34,7 @@ extern "C" } avr_err_t; 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_receive(const uint8_t addr, uint8_t *write_data, uint8_t write_size, uint8_t *read_data, uint8_t read_size, size_t delay); @@ -40,8 +46,7 @@ extern "C" #ifndef IICULTIMATE_H #define IICULTIMATE_H -#include -#include + // #include // #include diff --git a/zh_avr_i2c.c b/zh_avr_i2c.c index 0e40ce8..0471eed 100644 --- a/zh_avr_i2c.c +++ b/zh_avr_i2c.c @@ -1,30 +1,82 @@ #include "zh_avr_i2c.h" +#define ZH_ERROR_CHECK(cond, err, ...) \ + if (!(cond)) \ + { \ + return err; \ + } + +#define I2C_OK 0x01 +#define I2C_NACK 0x02 +#define I2C_COLLISION 0x04 +#define I2C_BUS_FAIL 0x08 + +#define TWCR_START ((1 << TWINT) | (1 << TWEN) | (1 << TWIE)) +#define I2C_MASTER_READ 1 +#define I2C_MASTER_WRITE 0 + +typedef enum +{ + MASTER_TX, + MASTER_RX, + MASTER_TX_RX, + MASTER_PR +} _work_mode_t; + +static EventGroupHandle_t _event_group_handle = NULL; +static uint8_t _target_i2c_address = 0; +volatile static uint8_t _work_mode = 0; + avr_err_t zh_avr_i2c_master_init(const bool pullup) { - i2c_PORT |= 1 << i2c_SCL | 1 << i2c_SDA; // Включим подтяжку на ноги, вдруг юзер на резисторы пожмотился - i2c_DDR &= ~(1 << i2c_SCL | 1 << i2c_SDA); - + _event_group_handle = xEventGroupCreate(); + ZH_ERROR_CHECK(_event_group_handle != NULL, AVR_ERR_NO_MEM); + cli(); DDRC &= ~(1 << PORTC5 | 1 << PORTC4); if (pullup == true) { PORTC |= 1 << PORTC5 | 1 << PORTC4; } + TWBR = ((F_CPU / 100000) - 16) / 2; + TWSR = 0xF8; + sei(); + return AVR_OK; +} - TWBR = 0x80; // Настроим битрейт - TWSR = 0x00; +avr_err_t zh_avr_i2c_master_probe(const uint8_t addr, TickType_t xTicksToWait) +{ + _work_mode = MASTER_PR; + _target_i2c_address = addr; + TWCR = TWCR_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) + { + return AVR_OK; + } + else if (bits & I2C_NACK) + { + return AVR_ERR_INVALID_RESPONSE; + } + else + { + return AVR_FAIL; + } } 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); @@ -54,509 +106,578 @@ uint8_t WorkIndex = 0; // Индекс лога ISR(TWI_vect) // Прерывание TWI Тут наше все. { - /* - PORTB ^= 0x01; // Дрыгаем ногой порта, для синхронизации логического анализатора и отметок вызова TWI - - - // Отладочный кусок. Вывод лога работы конечного автомата в буфер памяти, а потом. По окончании работы через UART на волю - if (WorkIndex <99) // Если лог не переполнен - { - if (TWSR) // Статус нулевой? - { - WorkLog[WorkIndex]= TWSR; // Пишем статус в лог - WorkIndex++; - } - else - { - WorkLog[WorkIndex]= 0xFF; // Если статус нулевой то вписываем FF - WorkIndex++; - } - } - */ switch (TWSR & 0xF8) // Отсекаем биты прескалера { - case 0x00: // Bus Fail (автобус сломался) - { - i2c_Do |= i2c_ERR_BF; - - TWCR = 0 << TWSTA | - 1 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Go! - - MACRO_i2c_WhatDo_ErrorOut break; - } - - case 0x08: // Старт был, а затем мы: - { - i2c_index = 0; // Обнуляем индекс буфера. - - if ((i2c_Do & i2c_type_msk) == i2c_sarp) // В зависимости от режима - { - i2c_SlaveAddress |= 0x01; // Шлем Addr+R - } - else // Или - { - i2c_SlaveAddress &= 0xFE; // Шлем Addr+W - } - - TWDR = i2c_SlaveAddress; // Адрес слейва - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Go! + case 0x00: // Bus error. + printf("00\n"); + TWCR = TWCR_START | (1 << TWSTO); + xEventGroupSetBitsFromISR(_event_group_handle, I2C_BUS_FAIL, NULL); break; - } - - case 0x10: // Повторный старт был, а затем мы - { - if ((i2c_Do & i2c_type_msk) == i2c_sawsarp) // В зависимости от режима + case 0x08: // A START condition has been transmitted. + printf("08\n"); + switch (_work_mode) { - i2c_SlaveAddress |= 0x01; // Шлем Addr+R - } - else - { - i2c_SlaveAddress &= 0xFE; // Шлем Addr+W - } - - // To Do: Добавить сюда обработку ошибок - - TWDR = i2c_SlaveAddress; // Адрес слейва - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Go! - break; - } - - case 0x18: // Был послан SLA+W получили ACK, а затем: - { - if ((i2c_Do & i2c_type_msk) == i2c_sawp) // В зависимости от режима - { - TWDR = i2c_Buffer[i2c_index]; // Шлем байт данных - i2c_index++; // Увеличиваем указатель буфера - - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Go! - } - - if ((i2c_Do & i2c_type_msk) == i2c_sawsarp) - { - i2c_PageAddrIndex = 0; // Обнулили указатель буфера адреса страницы. - - TWDR = i2c_PageAddress[i2c_PageAddrIndex]; // Или шлем адрес странцы (по сути тоже байт данных) - i2c_PageAddrIndex++; - // Увеличиваем указатель буфера страницы - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Go! - } - } - break; - - case 0x20: // Был послан SLA+W получили NACK - слейв либо занят, либо его нет дома. - { - i2c_Do |= i2c_ERR_NA; - // Код ошибки - TWCR = 0 << TWSTA | - 1 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Шлем шине Stop - - MACRO_i2c_WhatDo_ErrorOut // Обрабатываем событие ошибки; + case MASTER_TX: break; - } - - case 0x28: // Байт данных послали, получили ACK! (если sawp - это был байт данных. если sawsarp - байт адреса страницы) - { // А дальше: - if ((i2c_Do & i2c_type_msk) == i2c_sawp) // В зависимости от режима - { - if (i2c_index == i2c_ByteCount) // Если был байт данных последний - { - TWCR = 0 << TWSTA | - 1 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Шлем Stop - - MACRO_i2c_WhatDo_MasterOut // И выходим в обработку стопа - } - else - { - TWDR = i2c_Buffer[i2c_index]; // Либо шлем еще один байт - i2c_index++; - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Go! - } - } - - if ((i2c_Do & i2c_type_msk) == i2c_sawsarp) // В другом режиме мы - { - if (i2c_PageAddrIndex == i2c_PageAddrCount) // Если последний байт адреса страницы - { - TWCR = 1 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Запускаем Повторный старт! - } - else - { // Иначе - TWDR = i2c_PageAddress[i2c_PageAddrIndex]; // шлем еще один адрес страницы - i2c_PageAddrIndex++; // Увеличиваем индекс счетчика адреса страниц - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Go! - } - } - } - break; - - case 0x30: // Байт ушел, но получили NACK причин две. 1я передача оборвана слейвом и так надо. 2я слейв сглючил. - { - i2c_Do |= i2c_ERR_NK; // Запишем статус ошибки. Хотя это не факт, что ошибка. - - TWCR = 0 << TWSTA | - 1 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Шлем Stop - - MACRO_i2c_WhatDo_MasterOut // Отрабатываем событие выхода - + case MASTER_RX: break; - } - - case 0x38: // Коллизия на шине. Нашелся кто то поглавней - { - i2c_Do |= i2c_ERR_LP; // Ставим ошибку потери приоритета - - // Настраиваем индексы заново. - i2c_index = 0; - i2c_PageAddrIndex = 0; - - TWCR = 1 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Как только шина будет свободна - break; // попробуем передать снова. - } - - case 0x40: // Послали SLA+R получили АСК. А теперь будем получать байты - { - if (i2c_index + 1 == i2c_ByteCount) // Если буфер кончится на этом байте, то - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 0 << TWEA | - 1 << TWEN | - 1 << TWIE; // Требуем байт, а в ответ потом пошлем NACK(Disconnect) - } // Что даст понять слейву, что мол хватит гнать. И он отпустит шину - else - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 1 << TWEA | - 1 << TWEN | - 1 << TWIE; // Или просто примем байт и скажем потом ACK - } - - break; - } - - case 0x48: // Послали SLA+R, но получили NACK. Видать slave занят или его нет дома. - { - i2c_Do |= i2c_ERR_NA; - // Код ошибки No Answer - TWCR = 0 << TWSTA | - 1 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Шлем Stop - - MACRO_i2c_WhatDo_ErrorOut // Отрабатываем выходную ситуацию ошибки + case MASTER_TX_RX: + break; + case MASTER_PR: + TWDR = (_target_i2c_address << 1) | I2C_MASTER_READ; + TWCR = TWCR_START; + break; + default: break; - } - - case 0x50: // Приняли байт. - { - i2c_Buffer[i2c_index] = TWDR; // Забрали его из буфера - i2c_index++; - - // To Do: Добавить проверку переполнения буфера. А то мало ли что юзер затребует - - if (i2c_index + 1 == i2c_ByteCount) // Если остался еще один байт из тех, что мы хотели считать - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 0 << TWEA | - 1 << TWEN | - 1 << TWIE; // Затребываем его и потом пошлем NACK (Disconnect) - } - else - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 1 << TWEA | - 1 << TWEN | - 1 << TWIE; // Если нет, то затребываем следующий байт, а в ответ скажем АСК } break; - } - - case 0x58: // Вот мы взяли последний байт, сказали NACK слейв обиделся и отпал. - { - i2c_Buffer[i2c_index] = TWDR; // Взяли байт в буфер - TWCR = 0 << TWSTA | - 1 << TWSTO | - 1 << TWINT | - i2c_i_am_slave << TWEA | - 1 << TWEN | - 1 << TWIE; // Передали Stop - - MACRO_i2c_WhatDo_MasterOut // Отработали точку выхода - + case 0x10: // A repeated START condition has been transmitted. + printf("10\n"); + TWCR = TWCR_START | (1 << TWSTO); + break; + case 0x18: // SLA+W has been transmitted. ACK has been received. + printf("18\n"); + break; + case 0x20: // SLA+W has been transmitted. NOT ACK has been received. + printf("20\n"); + break; + case 0x28: // Data byte has been transmitted. ACK has been received. + printf("28\n"); + break; + case 0x30: // Data byte has been transmitted. NOT ACK has been received. + printf("30\n"); + break; + case 0x38: // Arbitration lost in SLA+W or data bytes. Arbitration lost in SLA+R or NOT ACK bit. + printf("38\n"); + break; + case 0x40: // SLA+R has been transmitted. ACK has been received. + printf("40\n"); + switch (_work_mode) + { + case MASTER_TX: break; - } + case MASTER_RX: + break; + case MASTER_TX_RX: + break; + case MASTER_PR: + TWCR = TWCR_START | (1 << TWSTO); + xEventGroupSetBitsFromISR(_event_group_handle, I2C_OK, NULL); + break; + default: + break; + } + break; + case 0x48: // SLA+R has been transmitted. NOT ACK has been received. + printf("48\n"); + switch (_work_mode) + { + case MASTER_TX: + break; + case MASTER_RX: + break; + case MASTER_TX_RX: + break; + case MASTER_PR: + TWCR = TWCR_START | (1 << TWSTO); + xEventGroupSetBitsFromISR(_event_group_handle, I2C_NACK, NULL); + break; + default: + break; + } + break; + case 0x50: // Data byte has been received. ACK has been returned. + printf("50\n"); + break; + case 0x58: // Data byte has been received. NOT ACK has been returned. + printf("58\n"); + break; + // printf("%d\n", (TWSR & 0xF8)); + // case 0x00: // Bus Fail (автобус сломался) + // { + + // i2c_Do |= i2c_ERR_BF; + + // TWCR = 0 << TWSTA | + // 1 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Go! + + // MACRO_i2c_WhatDo_ErrorOut break; + // } + + // case 0x08: // Старт был, а затем мы: + // { + // printf("08\n"); + // TWCR = (1 << TWINT) | (0 << TWEA) | (0 << TWSTA) | (0 << TWSTO) | (0 << TWWC) | (0 << TWEN) | (1 << TWIE); + // // i2c_index = 0; // Обнуляем индекс буфера. + + // // if ((i2c_Do & i2c_type_msk) == i2c_sarp) // В зависимости от режима + // // { + // // i2c_SlaveAddress |= 0x01; // Шлем Addr+R + // // } + // // else // Или + // // { + // // i2c_SlaveAddress &= 0xFE; // Шлем Addr+W + // // } + + // // TWDR = i2c_SlaveAddress; // Адрес слейва + // // TWCR = 0 << TWSTA | + // // 0 << TWSTO | + // // 1 << TWINT | + // // i2c_i_am_slave << TWEA | + // // 1 << TWEN | + // // 1 << TWIE; // Go! + // break; + // } + + // case 0x10: // Повторный старт был, а затем мы + // { + // if ((i2c_Do & i2c_type_msk) == i2c_sawsarp) // В зависимости от режима + // { + // i2c_SlaveAddress |= 0x01; // Шлем Addr+R + // } + // else + // { + // i2c_SlaveAddress &= 0xFE; // Шлем Addr+W + // } + + // // To Do: Добавить сюда обработку ошибок + + // TWDR = i2c_SlaveAddress; // Адрес слейва + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Go! + // break; + // } + + // case 0x18: // Был послан SLA+W получили ACK, а затем: + // { + // if ((i2c_Do & i2c_type_msk) == i2c_sawp) // В зависимости от режима + // { + // TWDR = i2c_Buffer[i2c_index]; // Шлем байт данных + // i2c_index++; // Увеличиваем указатель буфера + + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Go! + // } + + // if ((i2c_Do & i2c_type_msk) == i2c_sawsarp) + // { + // i2c_PageAddrIndex = 0; // Обнулили указатель буфера адреса страницы. + + // TWDR = i2c_PageAddress[i2c_PageAddrIndex]; // Или шлем адрес странцы (по сути тоже байт данных) + // i2c_PageAddrIndex++; + // // Увеличиваем указатель буфера страницы + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Go! + // } + // } + // break; + + // case 0x20: // Был послан SLA+W получили NACK - слейв либо занят, либо его нет дома. + // { + // i2c_Do |= i2c_ERR_NA; + // // Код ошибки + // TWCR = 0 << TWSTA | + // 1 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Шлем шине Stop + + // MACRO_i2c_WhatDo_ErrorOut // Обрабатываем событие ошибки; + // break; + // } + + // case 0x28: // Байт данных послали, получили ACK! (если sawp - это был байт данных. если sawsarp - байт адреса страницы) + // { // А дальше: + // if ((i2c_Do & i2c_type_msk) == i2c_sawp) // В зависимости от режима + // { + // if (i2c_index == i2c_ByteCount) // Если был байт данных последний + // { + // TWCR = 0 << TWSTA | + // 1 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Шлем Stop + + // MACRO_i2c_WhatDo_MasterOut // И выходим в обработку стопа + // } + // else + // { + // TWDR = i2c_Buffer[i2c_index]; // Либо шлем еще один байт + // i2c_index++; + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Go! + // } + // } + + // if ((i2c_Do & i2c_type_msk) == i2c_sawsarp) // В другом режиме мы + // { + // if (i2c_PageAddrIndex == i2c_PageAddrCount) // Если последний байт адреса страницы + // { + // TWCR = 1 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Запускаем Повторный старт! + // } + // else + // { // Иначе + // TWDR = i2c_PageAddress[i2c_PageAddrIndex]; // шлем еще один адрес страницы + // i2c_PageAddrIndex++; // Увеличиваем индекс счетчика адреса страниц + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Go! + // } + // } + // } + // break; + + // case 0x30: // Байт ушел, но получили NACK причин две. 1я передача оборвана слейвом и так надо. 2я слейв сглючил. + // { + // i2c_Do |= i2c_ERR_NK; // Запишем статус ошибки. Хотя это не факт, что ошибка. + + // TWCR = 0 << TWSTA | + // 1 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Шлем Stop + + // MACRO_i2c_WhatDo_MasterOut // Отрабатываем событие выхода + + // break; + // } + + // case 0x38: // Коллизия на шине. Нашелся кто то поглавней + // { + // i2c_Do |= i2c_ERR_LP; // Ставим ошибку потери приоритета + + // // Настраиваем индексы заново. + // i2c_index = 0; + // i2c_PageAddrIndex = 0; + + // TWCR = 1 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Как только шина будет свободна + // break; // попробуем передать снова. + // } + + // case 0x40: // Послали SLA+R получили АСК. А теперь будем получать байты + // { + // if (i2c_index + 1 == i2c_ByteCount) // Если буфер кончится на этом байте, то + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 0 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Требуем байт, а в ответ потом пошлем NACK(Disconnect) + // } // Что даст понять слейву, что мол хватит гнать. И он отпустит шину + // else + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 1 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Или просто примем байт и скажем потом ACK + // } + + // break; + // } + + // case 0x48: // Послали SLA+R, но получили NACK. Видать slave занят или его нет дома. + // { + // printf("48\n"); + // i2c_Do |= i2c_ERR_NA; + // // Код ошибки No Answer + // TWCR = 0 << TWSTA | + // 1 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Шлем Stop + + // MACRO_i2c_WhatDo_ErrorOut // Отрабатываем выходную ситуацию ошибки + // break; + // } + + // case 0x50: // Приняли байт. + // { + // i2c_Buffer[i2c_index] = TWDR; // Забрали его из буфера + // i2c_index++; + + // // To Do: Добавить проверку переполнения буфера. А то мало ли что юзер затребует + + // if (i2c_index + 1 == i2c_ByteCount) // Если остался еще один байт из тех, что мы хотели считать + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 0 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Затребываем его и потом пошлем NACK (Disconnect) + // } + // else + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 1 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Если нет, то затребываем следующий байт, а в ответ скажем АСК + // } + // break; + // } + + // case 0x58: // Вот мы взяли последний байт, сказали NACK слейв обиделся и отпал. + // { + // i2c_Buffer[i2c_index] = TWDR; // Взяли байт в буфер + // TWCR = 0 << TWSTA | + // 1 << TWSTO | + // 1 << TWINT | + // i2c_i_am_slave << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Передали Stop + + // MACRO_i2c_WhatDo_MasterOut // Отработали точку выхода + + // break; + // } // IIC Slave ============================================================================ - case 0x68: // RCV SLA+W Low Priority // Словили свой адрес во время передачи мастером - case 0x78: // RCV SLA+W Low Priority (Broadcast) // Или это был широковещательный пакет. Не важно - { - i2c_Do |= i2c_ERR_LP | i2c_Interrupted; // Ставим флаг ошибки Low Priority, а также флаг того, что мастера прервали + // case 0x68: // RCV SLA+W Low Priority // Словили свой адрес во время передачи мастером + // case 0x78: // RCV SLA+W Low Priority (Broadcast) // Или это был широковещательный пакет. Не важно + // { + // i2c_Do |= i2c_ERR_LP | i2c_Interrupted; // Ставим флаг ошибки Low Priority, а также флаг того, что мастера прервали - // Restore Trans after. - i2c_index = 0; // Подготовили прерваную передачу заново - i2c_PageAddrIndex = 0; - } // И пошли дальше. Внимание!!! break тут нет, а значит идем в "case 60" + // // Restore Trans after. + // i2c_index = 0; // Подготовили прерваную передачу заново + // i2c_PageAddrIndex = 0; + // } // И пошли дальше. Внимание!!! break тут нет, а значит идем в "case 60" - case 0x60: // RCV SLA+W Incoming? // Или просто получили свой адрес - case 0x70: // RCV SLA+W Incoming? (Broascast) // Или широковещательный пакет - { + // case 0x60: // RCV SLA+W Incoming? // Или просто получили свой адрес + // case 0x70: // RCV SLA+W Incoming? (Broascast) // Или широковещательный пакет + // { - i2c_Do |= i2c_Busy; // Занимаем шину. Чтобы другие не совались - i2c_SlaveIndex = 0; // Указатель на начало буфера слейва, Неважно какой буфер. Не ошибемся + // i2c_Do |= i2c_Busy; // Занимаем шину. Чтобы другие не совались + // i2c_SlaveIndex = 0; // Указатель на начало буфера слейва, Неважно какой буфер. Не ошибемся - if (i2c_MasterBytesRX == 1) // Если нам суждено принять всего один байт, то готовимся принять его - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 0 << TWEA | - 1 << TWEN | - 1 << TWIE; // Принять и сказать пошли все н... NACK! - } - else - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 1 << TWEA | - 1 << TWEN | - 1 << TWIE; // А если душа шире чем один байт, то сожрем и потребуем еще ACK! - } - break; - } + // if (i2c_MasterBytesRX == 1) // Если нам суждено принять всего один байт, то готовимся принять его + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 0 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Принять и сказать пошли все н... NACK! + // } + // else + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 1 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // А если душа шире чем один байт, то сожрем и потребуем еще ACK! + // } + // break; + // } - case 0x80: // RCV Data Byte // И вот мы приняли этот байт. Наш или широковещательный. Не важно - case 0x90: // RCV Data Byte (Broadcast) - { - i2c_InBuff[i2c_SlaveIndex] = TWDR; // Сжираем его в буфер. + // case 0x80: // RCV Data Byte // И вот мы приняли этот байт. Наш или широковещательный. Не важно + // case 0x90: // RCV Data Byte (Broadcast) + // { + // i2c_InBuff[i2c_SlaveIndex] = TWDR; // Сжираем его в буфер. - i2c_SlaveIndex++; // Сдвигаем указатель + // i2c_SlaveIndex++; // Сдвигаем указатель - if (i2c_SlaveIndex == i2c_MasterBytesRX - 1) // Свободно место всего под один байт? - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 0 << TWEA | - 1 << TWEN | - 1 << TWIE; // Приянть его и сказать NACK! - } - else - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 1 << TWEA | - 1 << TWEN | - 1 << TWIE; // Места еще дофига? Принять и ACK! - } - break; - } + // if (i2c_SlaveIndex == i2c_MasterBytesRX - 1) // Свободно место всего под один байт? + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 0 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Приянть его и сказать NACK! + // } + // else + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 1 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Места еще дофига? Принять и ACK! + // } + // break; + // } - case 0x88: // RCV Last Byte // Приянли последний байт - case 0x98: // RCV Last Byte (Broadcast) - { - i2c_InBuff[i2c_SlaveIndex] = TWDR; // Сожрали его в буфер + // case 0x88: // RCV Last Byte // Приянли последний байт + // case 0x98: // RCV Last Byte (Broadcast) + // { + // i2c_InBuff[i2c_SlaveIndex] = TWDR; // Сожрали его в буфер - if (i2c_Do & i2c_Interrupted) // Если у нас был прерываный сеанс от имени мастера - { - TWCR = 1 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 1 << TWEA | - 1 << TWEN | - 1 << TWIE; // Влепим в шину свой Start поскорей и сделаем еще одну попытку - } - else - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 1 << TWEA | - 1 << TWEN | - 1 << TWIE; // Если не было такого факта, то просто отвалимся и будем ждать - } + // if (i2c_Do & i2c_Interrupted) // Если у нас был прерываный сеанс от имени мастера + // { + // TWCR = 1 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 1 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Влепим в шину свой Start поскорей и сделаем еще одну попытку + // } + // else + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 1 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Если не было такого факта, то просто отвалимся и будем ждать + // } - MACRO_i2c_WhatDo_SlaveOut // И лениво отработаем наш выходной экшн для слейва - break; - } + // MACRO_i2c_WhatDo_SlaveOut // И лениво отработаем наш выходной экшн для слейва + // break; + // } - case 0xA0: // Ой, мы получили Повторный старт. Но чо нам с ним делать? - { + // case 0xA0: // Ой, мы получили Повторный старт. Но чо нам с ним делать? + // { - // Можно, конечно, сделать вспомогательный автомат, чтобы обрабатывать еще и адреса внутренних страниц, подобно еепромке. - // Но я не стал заморачиваться. В этом случае делается это тут. + // // Можно, конечно, сделать вспомогательный автомат, чтобы обрабатывать еще и адреса внутренних страниц, подобно еепромке. + // // Но я не стал заморачиваться. В этом случае делается это тут. - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 1 << TWEA | - 1 << TWEN | - 1 << TWIE; // просто разадресуемся, проигнорировав этот посыл - break; - } + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 1 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // просто разадресуемся, проигнорировав этот посыл + // break; + // } - case 0xB0: // Поймали свой адрес на чтение во время передачи Мастером - { - i2c_Do |= i2c_ERR_LP | i2c_Interrupted; // Ну чо, коды ошибки и флаг прерваной передачи. + // case 0xB0: // Поймали свой адрес на чтение во время передачи Мастером + // { + // i2c_Do |= i2c_ERR_LP | i2c_Interrupted; // Ну чо, коды ошибки и флаг прерваной передачи. - // Восстанавливаем индексы - i2c_index = 0; - i2c_PageAddrIndex = 0; + // // Восстанавливаем индексы + // i2c_index = 0; + // i2c_PageAddrIndex = 0; - } // Break нет! Идем дальше + // } // Break нет! Идем дальше - case 0xA8: // Либо просто словили свой адрес на чтение - { - i2c_SlaveIndex = 0; // Индексы слейвовых массивов на 0 + // case 0xA8: // Либо просто словили свой адрес на чтение + // { + // i2c_SlaveIndex = 0; // Индексы слейвовых массивов на 0 - TWDR = i2c_OutBuff[i2c_SlaveIndex]; // Чтож, отдадим байт из тех что есть. + // TWDR = i2c_OutBuff[i2c_SlaveIndex]; // Чтож, отдадим байт из тех что есть. - if (i2c_MasterBytesTX == 1) - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 0 << TWEA | - 1 << TWEN | - 1 << TWIE; // Если он последний, мы еще на NACK в ответ надеемся - } - else - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 1 << TWEA | - 1 << TWEN | - 1 << TWIE; // А если нет, то ACK ждем - } + // if (i2c_MasterBytesTX == 1) + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 0 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Если он последний, мы еще на NACK в ответ надеемся + // } + // else + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 1 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // А если нет, то ACK ждем + // } - break; - } + // break; + // } - case 0xB8: // Послали байт, получили ACK - { + // case 0xB8: // Послали байт, получили ACK + // { - i2c_SlaveIndex++; // Значит продолжаем дискотеку. Берем следующий байт - TWDR = i2c_OutBuff[i2c_SlaveIndex]; // Даем его мастеру + // i2c_SlaveIndex++; // Значит продолжаем дискотеку. Берем следующий байт + // TWDR = i2c_OutBuff[i2c_SlaveIndex]; // Даем его мастеру - if (i2c_SlaveIndex == i2c_MasterBytesTX - 1) // Если он последний был, то - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 0 << TWEA | - 1 << TWEN | - 1 << TWIE; // Шлем его и ждем NACK - } - else - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 1 << TWEA | - 0 << TWEN | - 1 << TWIE; // Если нет, то шлем и ждем ACK - } + // if (i2c_SlaveIndex == i2c_MasterBytesTX - 1) // Если он последний был, то + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 0 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Шлем его и ждем NACK + // } + // else + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 1 << TWEA | + // 0 << TWEN | + // 1 << TWIE; // Если нет, то шлем и ждем ACK + // } - break; - } + // break; + // } - case 0xC0: // Мы выслали последний байт, больше у нас нет, получили NACK - case 0xC8: // или ACK. В данном случае нам пох. Т.к. больше байтов у нас нет. - { - if (i2c_Do & i2c_Interrupted) // Если там была прерваная передача мастера - { // То мы ему ее вернем - i2c_Do &= i2c_NoInterrupted; - // Снимем флаг прерваности - TWCR = 1 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 1 << TWEA | - 1 << TWEN | - 1 << TWIE; // Сгенерим старт сразу же как получим шину. - } - else - { - TWCR = 0 << TWSTA | - 0 << TWSTO | - 1 << TWINT | - 1 << TWEA | - 1 << TWEN | - 1 << TWIE; // Если мы там одни, то просто отдадим шину - } - - MACRO_i2c_WhatDo_SlaveOut // И отработаем выход слейва. Впрочем, он тут - // Не особо то нужен. Разве что как сигнал, что мастер - break; // Нас почтил своим визитом. - } + // case 0xC0: // Мы выслали последний байт, больше у нас нет, получили NACK + // case 0xC8: // или ACK. В данном случае нам пох. Т.к. больше байтов у нас нет. + // { + // if (i2c_Do & i2c_Interrupted) // Если там была прерваная передача мастера + // { // То мы ему ее вернем + // i2c_Do &= i2c_NoInterrupted; + // // Снимем флаг прерваности + // TWCR = 1 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 1 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Сгенерим старт сразу же как получим шину. + // } + // else + // { + // TWCR = 0 << TWSTA | + // 0 << TWSTO | + // 1 << TWINT | + // 1 << TWEA | + // 1 << TWEN | + // 1 << TWIE; // Если мы там одни, то просто отдадим шину + // } + // MACRO_i2c_WhatDo_SlaveOut // И отработаем выход слейва. Впрочем, он тут + // // Не особо то нужен. Разве что как сигнал, что мастер + // break; // Нас почтил своим визитом. + // } default: break; } @@ -566,14 +687,14 @@ void DoNothing(void) // Функция пустышка, затыкать нес { } -void Init_i2c(void) // Настройка режима мастера -{ - i2c_PORT |= 1 << i2c_SCL | 1 << i2c_SDA; // Включим подтяжку на ноги, вдруг юзер на резисторы пожмотился - i2c_DDR &= ~(1 << i2c_SCL | 1 << i2c_SDA); +// void Init_i2c(void) // Настройка режима мастера +// { +// i2c_PORT |= 1 << i2c_SCL | 1 << i2c_SDA; // Включим подтяжку на ноги, вдруг юзер на резисторы пожмотился +// i2c_DDR &= ~(1 << i2c_SCL | 1 << i2c_SDA); - TWBR = 0x80; // Настроим битрейт - TWSR = 0x00; -} +// TWBR = 0x80; // Настроим битрейт +// TWSR = 0x00; +// } void Init_Slave_i2c(IIC_F Addr) // Настройка режима слейва (если нужно) {