Driver TWI/I2C - YouTube: Ciência Elétrica
Biblioteca Otimizada para Microcontroladores AVR
Carregando...
Procurando...
Nenhuma entrada encontrado
twi.c
Ir para a documentação desse arquivo.
1
10#include "twi.h"
11#include "twi_internal.h"
12#include "twi_config.h"
13#include <stddef.h>
14#include <avr/io.h>
15#include <avr/interrupt.h>
16#include <util/twi.h> // Para macros como TW_START, TW_MT_SLA_ACK
21#define TWI_TIMEOUT_LIMIT_DEFAULT 200 // ~200 interrupções sem progresso ? 100-200 ms em 100 kHz
22
28static size_t slave_rx_idx = 0;
29
35
44
45#if (TWI_DEBUG_MODE == 1)
47volatile uint8_t debug_twi_last_status = 0;
49volatile TWI_State_t debug_twi_last_state = TWI_STATE_IDLE;
51volatile uint8_t debug_twi_counter = 0;
52#endif
53
59static uint8_t twi_calc_twbr(TWI_Clock_t clock) {
60 uint32_t scl_freq = (clock == TWI_CLOCK_400KHZ) ? 400000UL : 100000UL;
61 return (uint8_t)((F_CPU / scl_freq) - 16UL) / 2UL;
62}
63
64// Implementação da inicialização do hardware
65TWI_Status_t twi_init(TWI_Mode_t mode, uint8_t address, TWI_Clock_t clock) {
66 if (mode != TWI_MODE_MASTER && mode != TWI_MODE_SLAVE) return TWI_ERROR_INVALID_ARG;
67
68 g_twi_txn.timeout_counter = 0;
70
71 // Configura clock
72 TWBR = twi_calc_twbr(clock);
73 TWSR = 0; // Prescaler 1
74
75 // Habilita TWI e interrupções
76 TWCR = (1 << TWEN) | (1 << TWIE);
77
78 if (mode == TWI_MODE_SLAVE) {
79 TWAR = (address << 1) | (TWI_ENABLE_GENERAL_CALL ? 1 : 0); // Endereço + GCA
80 TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA); // Habilita ACK para Slave
81 }
82
84 return TWI_OK;
85}
86
90void twi_deinit(void) {
91 TWCR = 0; // Desabilita o hardware, interrupções e o ACK
93 g_twi_txn.status = TWI_OK;
94}
95
96// Registra os callbacks para o modo Master.
101
102// Registra os callbacks para o modo Slave.
107
108// Inicia uma varredura (probe) no barramento para verificar a presença de um Slave.
109TWI_Status_t twi_master_start_probe(uint8_t slave_address) {
110 if (g_twi_txn.state != TWI_STATE_IDLE) return TWI_ERROR_BUS_BUSY;
111
113 g_twi_txn.slave_addr = slave_address;
114 g_twi_txn.tx_len = 0; // Sem dados, só probe
115 g_twi_txn.rx_len = 0;
116 g_twi_txn.on_complete = master_complete_cb;
117 g_twi_txn.on_error = error_cb;
118
119 // Inicia START
120 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE);
121 return TWI_OK;
122}
123
129ISR(TWI_vect) {
130 uint8_t twsr = TW_STATUS;
131 g_twi_txn.timeout_counter++;
132
133 #if (TWI_DEBUG_MODE == 1)
134 debug_twi_last_status = twsr;
135 debug_twi_last_state = g_twi_txn.state;
136 debug_twi_counter++;
137 #endif
138
139 // Verifica timeout (apenas se estamos em transação ativa)
140 if (g_twi_txn.state != TWI_STATE_IDLE &&
141 g_twi_txn.timeout_counter >= g_twi_txn.timeout_limit) {
142
145
146 // Libera o bus com STOP
147 TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN) | (1 << TWIE);
148
149 // Opcional: log de debug
150 #if (TWI_DEBUG_MODE == 1)
151 debug_twi_last_status = 0xFF; // valor especial para indicar timeout
152 #endif
153
154 // Não continua a execução normal da ISR
155 return;
156 }
157
158 switch (twsr) {
159 /* --- Master Start / Repeated Start --- */
160 case TW_START: // 0x08
161 g_twi_txn.timeout_counter = 0;
162
163 case TW_REP_START: // 0x10
164 if (g_twi_txn.tx_len > 0 && g_twi_txn.tx_idx < g_twi_txn.tx_len ) {
165 TWDR = (g_twi_txn.slave_addr << 1) | TW_WRITE;
167 } else {
168 TWDR = (g_twi_txn.slave_addr << 1) | TW_READ;
170 }
171 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
172 g_twi_txn.timeout_counter = 0;
173 break;
174
175 /* --- Master Transmitter --- */
176 case TW_MT_SLA_ACK: // 0x18
177 g_twi_txn.timeout_counter = 0;
178
179 case TW_MT_DATA_ACK: // 0x28
180 if (g_twi_txn.tx_idx < g_twi_txn.tx_len) {
181 TWDR = g_twi_txn.tx_buf[g_twi_txn.tx_idx++];
182 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
183 } else if (g_twi_txn.rx_len > 0) {
184 // Repeated Start para leitura
185 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE);
186 } else {
187 // Fim da transação: Envia STOP
188 g_twi_txn.status = TWI_OK;
190 TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN) | (1 << TWIE);
191 }
192 g_twi_txn.timeout_counter = 0;
193 break;
194
195 /* --- Master Receiver --- */
196 case TW_MR_SLA_ACK: // 0x40
197 g_twi_txn.rx_idx = 0;
198 // Se vamos ler mais de 1 byte, pede ACK para o primeiro dado
199 if (g_twi_txn.rx_len > 1) {
200 TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
201 } else {
202 // Se for apenas 1 byte, respondemos com NACK (TWEA=0) após recebe-lo.
203 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
204 }
205 g_twi_txn.timeout_counter = 0;
206 break;
207
208 case TW_MR_DATA_ACK: // 0x50
209 // Recebemos um byte e o Master deu ACK (pediu mais).
210 g_twi_txn.rx_buf[g_twi_txn.rx_idx++] = TWDR;
211
212 // Se o PRÓXIMO byte for o Último, devemos responder com NACK (TWEA=0).
213 if (g_twi_txn.rx_idx < (g_twi_txn.rx_len - 1)) {
214 TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
215 } else {
216 TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
217 }
218 g_twi_txn.timeout_counter = 0;
219 break;
220
221 case TW_MR_DATA_NACK: // 0x58
222 // Recebemos o último byte (Master deu NACK conforme planejado).
223 g_twi_txn.rx_buf[g_twi_txn.rx_idx++] = TWDR; // Salva o último byte
224 g_twi_txn.status = TWI_OK;
226 TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN) | (1 << TWIE);
227 g_twi_txn.timeout_counter = 0;
228 break;
229
230 /* --- Slave Receiver --- */
231 case TW_SR_SLA_ACK: // 0x60: Master quer escrever em nós
232 g_twi_txn.timeout_counter = 0;
233
234 case TW_SR_GCALL_ACK: // 0x70: Chamada geral recebida
235 slave_rx_idx = 0; // Reseta o índice de recepção
236 // Habilita ACK para receber o primeiro byte
237 TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
238 g_twi_txn.timeout_counter = 0;
239 break;
240
241 case TW_SR_DATA_ACK: // 0x80: Byte recebido com sucesso
242 g_twi_txn.timeout_counter = 0;
243
244 case TW_SR_GCALL_DATA_ACK:
247 }
248 // Continua dando ACK enquanto houver espaço no buffer
249 uint8_t sr_ack = (slave_rx_idx < TWI_RX_BUFFER_SIZE) ? (1 << TWEA) : 0;
250 TWCR = (1 << TWINT) | sr_ack | (1 << TWEN) | (1 << TWIE);
251 g_twi_txn.timeout_counter = 0;
252 break;
253
254 case TW_SR_STOP: // 0xA0: Master finalizou a escrita (STOP ou REPEATED START)
255 if (slave_receive_cb) {
256 // Notifica a aplicação com o buffer preenchido com segurança
258 }
259 slave_rx_idx = 0; // Limpa para próxima transação
260 // Volta a monitorar o barramento
261 TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
262 g_twi_txn.timeout_counter = 0;
263 break;
264
265 // Slave Transmitter
266 case TW_ST_SLA_ACK: // 0xA8: Master quer ler de nós
267 g_twi_txn.tx_idx = 0;
268 if (slave_transmit_cb) {
269 // Aplicação preenche o buffer interno de transmissão
271 }else {
272 g_twi_txn.tx_len = 0;
273 }
274 // Carrega o primeiro byte do buffer interno estável
275 TWDR = (g_twi_txn.tx_len > 0) ? slave_internal_tx_buffer[g_twi_txn.tx_idx++] : 0x00;
276 TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
277 g_twi_txn.timeout_counter = 0;
278 break;
279
280 case TW_ST_DATA_ACK: // 0xB8: Master recebeu e pediu o próximo
281 if (g_twi_txn.tx_idx < g_twi_txn.tx_len) {
282 TWDR = slave_internal_tx_buffer[g_twi_txn.tx_idx++];
283 } else {
284 TWDR = 0x00; // Envia dummy se o Master pedir mais do que o provido
285 }
286 TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
287 g_twi_txn.timeout_counter = 0;
288 break;
289
290 case TW_ST_DATA_NACK: // 0xC0: Master enviou NACK (Fim da leitura)
291 g_twi_txn.timeout_counter = 0;
292
293 case TW_ST_LAST_DATA: // 0xC8: Enviamos o último byte possível
294 TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
295 // Transação Slave concluída
296 g_twi_txn.timeout_counter = 0;
297 break;
298
299 /* === TRATAMENTO DE ERROS === */
300 case TW_MT_SLA_NACK:
301 g_twi_txn.timeout_counter = 0;
302
303 case TW_MR_SLA_NACK:
304 g_twi_txn.status = TWI_ERROR_NACK;
306 TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN) | (1 << TWIE);
307 g_twi_txn.timeout_counter = 0;
308 break;
309
310 case TW_MT_DATA_NACK:
311 g_twi_txn.status = TWI_ERROR_NACK;
313 TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN) | (1 << TWIE);
314 g_twi_txn.timeout_counter = 0;
315 break;
316
317 default:
318 TWCR = (1 << TWINT) | (1 << TWEA) | (1 << TWEN) | (1 << TWIE);
319 g_twi_txn.timeout_counter = 0;
320 break;
321 }
322
323 // Finalização das transações Master (conforme seu padrão)
324 if (g_twi_txn.state == TWI_STATE_STOP || g_twi_txn.state == TWI_STATE_ERROR) {
325 TWI_Status_t res = g_twi_txn.status;
328 else if (error_cb) error_cb(res);
329 }
330}
331
332TWI_Status_t twi_master_start_write(uint8_t slave_address, const uint8_t* data, size_t length) {
333 if (g_twi_txn.state != TWI_STATE_IDLE) return TWI_ERROR_BUS_BUSY;
334
336 g_twi_txn.slave_addr = slave_address;
337 g_twi_txn.tx_buf = data;
338 g_twi_txn.tx_len = length;
339 g_twi_txn.tx_idx = 0;
340 g_twi_txn.rx_len = 0;
341
342 // Inicia START condition
343 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE);
344 return TWI_OK;
345}
346
347// Master Start Read
348TWI_Status_t twi_master_start_read(uint8_t slave_address, uint8_t* data, size_t length) {
349 if (g_twi_txn.state != TWI_STATE_IDLE) return TWI_ERROR_BUS_BUSY;
351 g_twi_txn.slave_addr = slave_address;
352 g_twi_txn.tx_len = 0;
353 g_twi_txn.rx_buf = data;
354 g_twi_txn.rx_len = length;
355 g_twi_txn.rx_idx = 0;
356 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE);
357 return TWI_OK;
358}
359
360// Master Start Write-Read (combinada, com REPEATED START)
362 const uint8_t* write_data, size_t write_length,
363 uint8_t* read_data, size_t read_length) {
364 if (g_twi_txn.state != TWI_STATE_IDLE) return TWI_ERROR_BUS_BUSY;
365
367 g_twi_txn.slave_addr = slave_address;
368 g_twi_txn.tx_buf = write_data; // Ponteiro para o buffer de escrita do usuário
369 g_twi_txn.tx_len = write_length;
370 g_twi_txn.tx_idx = 0;
371 g_twi_txn.rx_buf = read_data; // Ponteiro para onde o usuário quer salvar a leitura
372 g_twi_txn.rx_len = read_length;
373 g_twi_txn.rx_idx = 0;
374 g_twi_txn.status = TWI_OK;
375
376 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE);
377 return TWI_OK;
378}
379
380// Função auxiliar para avançar FSM (se necessário, mas aqui tudo na ISR)
382 // Vazio por enquanto; lógica na ISR
383}
384
386 // Opcional: se precisar de polling híbrido, mas com interrupções puras, retorne TWI_OK
387 return TWI_OK;
388}
389
391 if (g_twi_txn.state == TWI_STATE_IDLE) {
392 return TWI_BUS_IDLE;
393 }
394
395 if (g_twi_txn.state == TWI_STATE_ERROR || g_twi_txn.status != TWI_OK) {
396 return TWI_BUS_ERROR;
397 }
398
399 return TWI_BUS_BUSY;
400}
401
418TWI_Status_t twi_master_write_read(uint8_t slave_addr, const uint8_t* tx_data, size_t tx_len, uint8_t* rx_data, size_t rx_len) {
419 // Verifica se a máquina de estados está ociosa. Se não estiver, evita sobreposição.
420 if (g_twi_txn.state != TWI_STATE_IDLE) return TWI_ERROR_BUS_BUSY;
421
422 // Configura os parâmetros da transação na estrutura global g_twi_txn
423 g_twi_txn.state = TWI_STATE_START; // Define que o próximo passo é enviar o START
424 g_twi_txn.slave_addr = slave_addr; // Armazena o endereço (será deslocado na ISR)
425
426 // Configuração de Escrita
427 g_twi_txn.tx_buf = tx_data; // Aponta para os dados de saída
428 g_twi_txn.tx_len = tx_len; // Define quantos bytes enviar antes do Repeated Start
429 g_twi_txn.tx_idx = 0; // Reseta o índice de transmissão
430
431 // Configuração de Leitura
432 g_twi_txn.rx_buf = rx_data; // Define o destino dos dados de entrada
433 g_twi_txn.rx_len = rx_len; // Define quantos bytes esperar do escravo
434 g_twi_txn.rx_idx = 0; // Reseta o índice de recepção
435
436 g_twi_txn.status = TWI_OK; // Reseta status de erro anterior
437
438 // Vincula o callback registrado pelo usuário é transação atual
439 g_twi_txn.on_complete = master_complete_cb;
440
441 /*
442 * Disparo do Hardware:
443 * TWINT: Limpa a flag de interrupção para iniciar a operação.
444 * TWSTA: Gera a condição de START no barramento.
445 * TWEN: Mantém o módulo TWI habilitado.
446 * TWIE: Habilita a interrupção para que o restante da transação ocorra na ISR.
447 */
448 TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE);
449
450 return TWI_OK;
451}
void on_complete(TWI_Status_t st, const uint8_t *data, size_t len)
Callback de conclusão para transações Master.
Definição example1.c:105
size_t on_transmit(uint8_t *buffer, size_t max_len)
Callback de transmissão (Slave -> Master).
Definição example2.c:115
void on_receive(const uint8_t *dados, size_t len)
Callback de recebimento (Master -> Slave).
Definição example2.c:97
Estrutura de controle para a transação TWI ativa.
Definição twi_internal.h:37
void twi_handle_state(void)
Gerenciador principal da Máquina de Estados.
Definição twi.c:381
void twi_master_register_callbacks(TWI_Master_Complete_Callback_t on_complete, TWI_Error_Callback_t on_error)
Registra os callbacks de eventos para o modo Master.
Definição twi.c:97
static uint8_t slave_internal_rx_buffer[TWI_RX_BUFFER_SIZE]
Buffer interno para recepção de dados no modo Slave.
Definição twi.c:24
void twi_slave_register_callbacks(TWI_Slave_Receive_Callback_t on_receive, TWI_Slave_Transmit_Callback_t on_transmit)
Registra os callbacks de eventos para o modo Slave.
Definição twi.c:103
TWI_Status_t twi_master_start_read(uint8_t slave_address, uint8_t *data, size_t length)
Inicia leitura assíncrona de dados como Master.
Definição twi.c:348
static TWI_Slave_Transmit_Callback_t slave_transmit_cb
Definição twi.c:42
static uint8_t twi_calc_twbr(TWI_Clock_t clock)
Calcula o valor do registrador TWBR baseado na frequência de CPU e SCL desejada.
Definição twi.c:59
static TWI_Error_Callback_t error_cb
Definição twi.c:40
#define TWI_TIMEOUT_LIMIT_DEFAULT
Limite padrão de timeout para evitar travamento do barramento.
Definição twi.c:21
ISR(TWI_vect)
Vetor de Interrupção TWI.
Definição twi.c:129
TWI_Status_t twi_master_start_probe(uint8_t slave_address)
Realiza um "ping" no endereço para verificar se o Slave está presente.
Definição twi.c:109
TWI_Status_t twi_slave_process(void)
Processa eventos pendentes no Slave.
Definição twi.c:385
static TWI_Slave_Receive_Callback_t slave_receive_cb
Definição twi.c:41
static TWI_Master_Complete_Callback_t master_complete_cb
Definição twi.c:39
TWI_Status_t twi_init(TWI_Mode_t mode, uint8_t address, TWI_Clock_t clock)
Inicializa o módulo TWI.
Definição twi.c:65
TWI_Status_t twi_master_start_write_read(uint8_t slave_address, const uint8_t *write_data, size_t write_length, uint8_t *read_data, size_t read_length)
Inicia uma transação combinada (Escrita seguida de Leitura) com Repeated Start.
Definição twi.c:361
static size_t slave_rx_idx
Índice atual do buffer de recepção do Slave.
Definição twi.c:28
void twi_deinit(void)
Desabilita o módulo TWI e reseta o estado da transação.
Definição twi.c:90
TWI_Status_t twi_master_start_write(uint8_t slave_address, const uint8_t *data, size_t length)
Inicia envio assíncrono de dados como Master.
Definição twi.c:332
TWI_Status_t twi_master_write_read(uint8_t slave_addr, const uint8_t *tx_data, size_t tx_len, uint8_t *rx_data, size_t rx_len)
Inicia uma transação combinada de escrita seguida de leitura (Repeated Start).
Definição twi.c:418
TWI_BusState_t twi_get_bus_status(void)
Retorna o estado atual do barramento.
Definição twi.c:390
static uint8_t slave_internal_tx_buffer[TWI_RX_BUFFER_SIZE]
Buffer interno para transmissão de dados no modo Slave.
Definição twi.c:26
Interface pública do driver TWI/I2C para AVR.
#define F_CPU
Define a frequência da CPU caso não tenha sido definida via compilador.
Definição twi.h:13
TWI_BusState_t
Estados lógicos do barramento TWI.
Definição twi.h:111
@ TWI_BUS_ERROR
Definição twi.h:114
@ TWI_BUS_BUSY
Definição twi.h:113
@ TWI_BUS_IDLE
Definição twi.h:112
Configurações estáticas do driver TWI.
#define TWI_ENABLE_GENERAL_CALL
Habilita a resposta ao endereço de chamada geral (0x00).
Definição twi_config.h:41
#define TWI_RX_BUFFER_SIZE
Tamanho dos buffers internos de recepção e transmissão do Slave.
Definição twi_config.h:54
Definições internas e Máquina de Estados (FSM) do driver TWI.
TWI_State_t
Estados da Máquina de Estados Finita (FSM) do TWI.
Definição twi_internal.h:19
@ TWI_STATE_SLA_R
Definição twi_internal.h:23
@ TWI_STATE_STOP
Definição twi_internal.h:27
@ TWI_STATE_START
Definição twi_internal.h:21
@ TWI_STATE_SLA_W
Definição twi_internal.h:22
@ TWI_STATE_IDLE
Definição twi_internal.h:20
@ TWI_STATE_ERROR
Definição twi_internal.h:28
volatile TWI_Transaction_t g_twi_txn
Instância global da transação ativa.
Definição twi.c:34
size_t(* TWI_Slave_Transmit_Callback_t)(uint8_t *data, size_t max_length)
Callback para o modo Slave: acionado quando o Master solicita dados.
Definição twi_types.h:54
TWI_Mode_t
Modos de operação do módulo TWI.
Definição twi_types.h:16
@ TWI_MODE_MASTER
Definição twi_types.h:17
@ TWI_MODE_SLAVE
Definição twi_types.h:18
TWI_Status_t
Códigos de status e erro para operações TWI.
Definição twi_types.h:32
@ TWI_OK
Definição twi_types.h:33
@ TWI_ERROR_BUS_BUSY
Definição twi_types.h:35
@ TWI_ERROR_TIMEOUT
Definição twi_types.h:37
@ TWI_ERROR_NACK
Definição twi_types.h:34
@ TWI_ERROR_INVALID_ARG
Definição twi_types.h:38
void(* TWI_Master_Complete_Callback_t)(TWI_Status_t status, const uint8_t *data, size_t length)
Callback de conclusão para o modo Master.
Definição twi_types.h:62
void(* TWI_Slave_Receive_Callback_t)(const uint8_t *data, size_t length)
Callback para o modo Slave: acionado após o recebimento de dados.
Definição twi_types.h:46
void(* TWI_Error_Callback_t)(TWI_Status_t error)
Callback genérico para tratamento de erros no barramento.
Definição twi_types.h:68
TWI_Clock_t
Frequências de clock (SCL) suportadas para o barramento.
Definição twi_types.h:24
@ TWI_CLOCK_400KHZ
Definição twi_types.h:26