Configuración de un ATtiny45 como maestro I2C - SCL cambia a bajo, pero se niega a cambiar a alto

2

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?

El

Capí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
        }
}
    
pregunta jippie

2 respuestas

0

Para hacer que el pin se mueva hacia arriba y hacia abajo, cambié el bucle principal con una escritura a USISR de la siguiente manera:

    while ( 1 ) {
            // Toggle SCL low
            USICR = maskUSICR |                                     // Universal Serial Interface Control Register
                    _BS( USITC );                                   // Release SCL, Toggle Clock Port Pin

            USISR   =                                               // SCL is released by setting correct status bits
                    _BS( USISIF ) |
                    _BS( USIOIF ) |
                    _BS( USIPF )  |
                    _BS( USIDC )  |
                    _BC( USICNT0 );

            // Toggle hearbeat Pin
            PINB = _BS( heartbeatPin );                             // Toggle heartbeat pin
    }
    
respondido por el jippie
1

La forma idiomáticamente correcta de establecer un bit en AVR-GCC es: value |= _BV(bit_number) . Del mismo modo, para aclarar un poco es: value &= ~_BV(bit_number) ...

¿Ha echado un vistazo a AVR310 de la aplicación Atmel: uso del módulo USI como maestro I2C ? Aquí hay un enlace al software que lo acompaña.

    
respondido por el vicatcu

Lea otras preguntas en las etiquetas