702 lines
23 KiB
C
702 lines
23 KiB
C
#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 I2C_START ((1 << TWINT) | (1 << TWEN) | (1 << TWIE))
|
||
#define I2C_MASTER_READ 1
|
||
#define I2C_MASTER_WRITE 0
|
||
|
||
typedef enum
|
||
{
|
||
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();
|
||
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;
|
||
}
|
||
|
||
avr_err_t zh_avr_i2c_master_probe(const uint8_t addr, TickType_t xTicksToWait)
|
||
{
|
||
_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)
|
||
{
|
||
return AVR_OK;
|
||
}
|
||
else if ((bits & I2C_NACK) != 0)
|
||
{
|
||
return AVR_ERR_INVALID_RESPONSE;
|
||
}
|
||
else
|
||
{
|
||
return AVR_FAIL;
|
||
}
|
||
}
|
||
|
||
ISR(TWI_vect)
|
||
{
|
||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||
switch (TWSR & 0xF8) // Отсекаем биты прескалера
|
||
{
|
||
case 0x00: // Bus error.
|
||
printf("00\n");
|
||
TWCR = I2C_START | (1 << TWSTO);
|
||
xEventGroupSetBitsFromISR(_event_group_handle, I2C_BUS_FAIL, &xHigherPriorityTaskWoken);
|
||
break;
|
||
case 0x08: // A START condition has been transmitted.
|
||
printf("08\n");
|
||
switch (_work_mode)
|
||
{
|
||
case MASTER_WRITE:
|
||
TWDR = (_target_i2c_address << 1) | I2C_MASTER_WRITE;
|
||
// TWCR = I2C_START;
|
||
break;
|
||
case MASTER_READ:
|
||
TWDR = (_target_i2c_address << 1) | I2C_MASTER_READ;
|
||
// 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);
|
||
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");
|
||
TWCR = I2C_START | (1 << TWSTO);
|
||
xEventGroupSetBitsFromISR(_event_group_handle, I2C_COLLISION, &xHigherPriorityTaskWoken);
|
||
break;
|
||
case 0x40: // SLA+R has been transmitted. ACK has been received.
|
||
printf("40\n");
|
||
switch (_work_mode)
|
||
{
|
||
case MASTER_WRITE:
|
||
break;
|
||
case MASTER_READ:
|
||
break;
|
||
case MASTER_WRITE_REG:
|
||
break;
|
||
case MASTER_READ_REG:
|
||
break;
|
||
case MASTER_PROBE:
|
||
TWCR = I2C_START | (1 << TWSTO);
|
||
xEventGroupSetBitsFromISR(_event_group_handle, I2C_OK, &xHigherPriorityTaskWoken);
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
break;
|
||
case 0x48: // SLA+R has been transmitted. NOT ACK has been received.
|
||
printf("48\n");
|
||
TWCR = I2C_START | (1 << TWSTO);
|
||
xEventGroupSetBitsFromISR(_event_group_handle, I2C_NACK, &xHigherPriorityTaskWoken);
|
||
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, а также флаг того, что мастера прервали
|
||
|
||
// // 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) // Или широковещательный пакет
|
||
// {
|
||
|
||
// 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;
|
||
// }
|
||
|
||
// case 0x80: // RCV Data Byte // И вот мы приняли этот байт. Наш или широковещательный. Не важно
|
||
// case 0x90: // RCV Data Byte (Broadcast)
|
||
// {
|
||
// i2c_InBuff[i2c_SlaveIndex] = TWDR; // Сжираем его в буфер.
|
||
|
||
// 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;
|
||
// }
|
||
|
||
// 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; // Если не было такого факта, то просто отвалимся и будем ждать
|
||
// }
|
||
|
||
// MACRO_i2c_WhatDo_SlaveOut // И лениво отработаем наш выходной экшн для слейва
|
||
// break;
|
||
// }
|
||
|
||
// case 0xA0: // Ой, мы получили Повторный старт. Но чо нам с ним делать?
|
||
// {
|
||
|
||
// // Можно, конечно, сделать вспомогательный автомат, чтобы обрабатывать еще и адреса внутренних страниц, подобно еепромке.
|
||
// // Но я не стал заморачиваться. В этом случае делается это тут.
|
||
|
||
// TWCR = 0 << TWSTA |
|
||
// 0 << TWSTO |
|
||
// 1 << TWINT |
|
||
// 1 << TWEA |
|
||
// 1 << TWEN |
|
||
// 1 << TWIE; // просто разадресуемся, проигнорировав этот посыл
|
||
// break;
|
||
// }
|
||
|
||
// case 0xB0: // Поймали свой адрес на чтение во время передачи Мастером
|
||
// {
|
||
// i2c_Do |= i2c_ERR_LP | i2c_Interrupted; // Ну чо, коды ошибки и флаг прерваной передачи.
|
||
|
||
// // Восстанавливаем индексы
|
||
// i2c_index = 0;
|
||
// i2c_PageAddrIndex = 0;
|
||
|
||
// } // Break нет! Идем дальше
|
||
|
||
// case 0xA8: // Либо просто словили свой адрес на чтение
|
||
// {
|
||
// i2c_SlaveIndex = 0; // Индексы слейвовых массивов на 0
|
||
|
||
// 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 ждем
|
||
// }
|
||
|
||
// break;
|
||
// }
|
||
|
||
// case 0xB8: // Послали байт, получили ACK
|
||
// {
|
||
|
||
// 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
|
||
// }
|
||
|
||
// 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;
|
||
}
|
||
if (xHigherPriorityTaskWoken == pdTRUE)
|
||
{
|
||
portYIELD();
|
||
};
|
||
} |