diff --git a/README.md b/README.md index 96a63bb..775f699 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,51 @@ # zh_avr_i2c AVR library for I2C bus. + +#include "avr/io.h" +#include "stdio.h" +#include "zh_avr_i2c.h" + +#define BAUD_RATE 9600 +#define BAUD_PRESCALE (F_CPU / 16 / BAUD_RATE - 1) + +int usart(char byte, FILE *stream) +{ + while ((UCSR0A & (1 << UDRE0)) == 0) + { + } + UDR0 = byte; + return 0; +} +FILE uart = FDEV_SETUP_STREAM(usart, NULL, _FDEV_SETUP_WRITE); + +void i2c_example_task(void *pvParameters) +{ + zh_avr_i2c_master_init(false); + avr_err_t err = zh_avr_i2c_master_probe(0x38, 100 / portTICK_PERIOD_MS); + switch (err) + { + case AVR_OK: + printf("Slave Answered.\n"); + break; + case AVR_ERR_INVALID_RESPONSE: + printf("Slave Not Answer.\n"); + break; + default: + printf("Bus Error.\n"); + break; + } + vTaskDelete(NULL); +} + +int main(void) +{ + UBRR0H = (BAUD_PRESCALE >> 8); + UBRR0L = BAUD_PRESCALE; + UCSR0B = (1 << RXEN0) | (1 << TXEN0); + UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); + stdout = &uart; + xTaskCreate(i2c_example_task, "i2c example task", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, NULL); + vTaskStartScheduler(); + return 0; +} \ No newline at end of file diff --git a/zh_avr_i2c.c b/zh_avr_i2c.c index 0471eed..3b0974c 100644 --- a/zh_avr_i2c.c +++ b/zh_avr_i2c.c @@ -11,7 +11,7 @@ #define I2C_COLLISION 0x04 #define I2C_BUS_FAIL 0x08 -#define TWCR_START ((1 << TWINT) | (1 << TWEN) | (1 << TWIE)) +#define I2C_START ((1 << TWINT) | (1 << TWEN) | (1 << TWIE)) #define I2C_MASTER_READ 1 #define I2C_MASTER_WRITE 0 @@ -47,7 +47,7 @@ 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); + 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) { @@ -106,12 +106,13 @@ uint8_t WorkIndex = 0; // Индекс лога ISR(TWI_vect) // Прерывание TWI Тут наше все. { + BaseType_t xHigherPriorityTaskWoken = pdFALSE; switch (TWSR & 0xF8) // Отсекаем биты прескалера { case 0x00: // Bus error. printf("00\n"); - TWCR = TWCR_START | (1 << TWSTO); - xEventGroupSetBitsFromISR(_event_group_handle, I2C_BUS_FAIL, NULL); + 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"); @@ -125,7 +126,7 @@ ISR(TWI_vect) // Прерывание TWI Тут наше все. break; case MASTER_PR: TWDR = (_target_i2c_address << 1) | I2C_MASTER_READ; - TWCR = TWCR_START; + TWCR = I2C_START; break; default: break; @@ -133,7 +134,7 @@ ISR(TWI_vect) // Прерывание TWI Тут наше все. break; case 0x10: // A repeated START condition has been transmitted. printf("10\n"); - TWCR = TWCR_START | (1 << TWSTO); + TWCR = I2C_START | (1 << TWSTO); break; case 0x18: // SLA+W has been transmitted. ACK has been received. printf("18\n"); @@ -149,6 +150,8 @@ ISR(TWI_vect) // Прерывание TWI Тут наше все. 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"); @@ -161,8 +164,8 @@ ISR(TWI_vect) // Прерывание TWI Тут наше все. case MASTER_TX_RX: break; case MASTER_PR: - TWCR = TWCR_START | (1 << TWSTO); - xEventGroupSetBitsFromISR(_event_group_handle, I2C_OK, NULL); + TWCR = I2C_START | (1 << TWSTO); + xEventGroupSetBitsFromISR(_event_group_handle, I2C_OK, &xHigherPriorityTaskWoken); break; default: break; @@ -170,21 +173,8 @@ ISR(TWI_vect) // Прерывание TWI Тут наше все. 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; - } + 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"); @@ -681,6 +671,10 @@ ISR(TWI_vect) // Прерывание TWI Тут наше все. default: break; } + if (xHigherPriorityTaskWoken == pdTRUE) + { + portYIELD(); + }; } void DoNothing(void) // Функция пустышка, затыкать несуществующие ссылки