Otro pin, otra pregunta: Sin embargo, está estrechamente relacionado con Configuración de un ATtiny45 como maestro I2C - SDA se queda bajo esta es una pregunta diferente.
Estoy tratando de controlar un DAC desde un ATtiny45, pero de alguna manera la línea SCL se atasca después de alternar una vez . Para encontrar el problema en el código hice lo siguiente:
- Simplifiqué el circuito solo al controlador con las resistencias pull up, no hay un esclavo I2C conectado;
- Simplifiqué la base del código C al mínimo para reproducir el problema.
El siguiente es el resultado hasta ahora:
- Cuando quito la conmutación del bucle principal, la línea SCL es alta;
- Cuando incluyo el código de activación de SCL: Después de la primera activación, la línea de SCL está baja;
- El pin de latido del corazón prueba que el bucle principal está activo.
Lo que pasa:
- Después de la primera vez que escribo a USITC-bit en USICR, SCL cambia a bajo, después de eso queda bloqueado.
USITC Interfaz de serie universal que alterna el pin del puerto del reloj
USICR Registro de control de interfaz de serie universal
SCL Perno del reloj serial I2C
Lo que espero:
- Cada vez que escribo en USITC-bit en USICR, espero que SCL se mueva hacia arriba o hacia abajo (al mismo ritmo que el pin de latido).
Al escribir una ubicación en este bit, se alterna el valor USCK / SCL de 0 a 1, o de 1 a 0. La conmutación es independiente de la configuración en el registro de dirección de datos, pero si el valor del puerto debe ser mostrado en el pin, el pin DDR correspondiente debe configurarse como salida (para uno). Esta característica permite una fácil generación de reloj al implementar dispositivos maestros.
Mi pregunta es: ¿Qué estoy haciendo mal, cómo puedo hacer que SCL siga la alternancia de USITC?
ElCapítulo 15 de la hoja de datos trata sobre la interfaz de serie universal y estoy intentando configurar I2C / TWI como se describe en 15.3.4 y más adelante.
Aquí está el código del programa minimizado:
#include <avr/io.h>
#include <util/delay.h>
#define _BS(bit) ( 1 << ( bit ) )
#define _BC(bit) ( 0 << ( bit ) )
const uint8_t heartbeatPin = PB3;
const uint8_t sdaPin = PB0;
const uint8_t sclPin = PB2;
const uint8_t maskUSICR = // Universal Serial Interface Control Register
_BC( USISIE ) | // (rw) disable USI Start Condition Interrupt Enable
_BC( USIOIE ) | // (rw) disable USI Counter Overflow Interrupt Enable
_BS( USIWM1 ) | _BC( USIWM0 ) | // (rw) Two wire mode, not using counter overflow
_BC( USICS1 ) | _BC( USICS0 ) | // (rw) Clock select => software clock strobe (USICLK)
_BC( USICLK ) | // (-w) Clock strobe
_BC( USITC ); // (-w) Toggle Port Pin
/*
ATtiny45
pin 1 2 3 4 5 6 7 8
name PB5 PB3 PB4 GND PB0 PB1 PB2 VCC
func !RESET h/beat GND SDA SCL VCC
*/
int main( void ) {
//
// Setup
//
// Setting up output drivers
DDRB = // Port B Data Direction Register.
_BS( heartbeatPin ) | // PB3 output driver enable
_BS( sdaPin ) | // SDA output driver enable
_BS( sclPin ); // SCL output driver enable
// Enable SCL & SDA
PORTB |= // PORT B output register
_BS( sclPin ) | // Set SCL pin high
_BS( sdaPin ); // Set SDA pin high
// Set up I2C / TWI
USICR = // Universal Serial Interface Control Register
maskUSICR; // I2C, no interrupts, software clock
//
// Endless loop
//
while ( 1 ) {
// Toggle SCL high
USICR = maskUSICR | // Universal Serial Interface Control Register
_BS( USITC ); // Release SCL, Toggle Clock Port Pin
// Toggle hearbeat Pin
PINB = _BS( heartbeatPin ); // Toggle heartbeat pin
}
}