ATMega168 La transmisión SPI no se iniciará

2

Escenario

Tengo un ATMega168 utilizando un cristal externo de 10MHz. El bit de fusible DIV / 8 no está configurado. El procesador toma las salidas de 4 codificadores rotatorios en cuadratura. Su información de dirección de rotación se decodifica utilizando interrupciones de cambio de pin y los estados de pin. La información de rotación se convierte en códigos de control y se envía a través de SPI a otro procesador que maneja algunos motores.

Problema

En el código listado, la información de la dirección de rotación se decodifica y se convierte en códigos de control tal como se diseñó, y se verificó en el hardware. La transmisión SPI no se inicia. Al observar los pines SPI en el visor, el pin SS permanece alto y el SCK y MOSI se mantienen bajos.

Otras dos personas han mirado este código aparte de mí. Sé que tengo que pasar por alto algo simple. ¿Por qué no comienza la transmisión?

/*Ports:
D.7..D.0 - 4x quadrature rotary encoders, triggering pin change interrupts
B.5 - SCK (SPI clock line)
B.3 - MOSI(SPI data line)
B.2 - !SS (SPI chip select)

This module interfaces with the rotary encoders, converts their 
rotation to control commands, and transfers these commands over 
the serial peripheral interface to the motor controller.
*/

#define LASER_X_L 28
#define LASER_X_R 56
#define LASER_Y_D 84
#define LASER_Y_U 112
#define MIRROR_X_L 140
#define MIRROR_X_R 168
#define MIRROR_Y_D 196
#define MIRROR_Y_U 224
#define NOTHING 0

#include <avr/io.h>
#include <avr/interrupt.h>

void initPorts(void); //set up function for GPIO ports
void initExtInt(void); //set up function for external interrupts
void initSPI(void); //set up function for SPI

int main(void)
{
    initPorts(); //call port set up function
    initExtInt(); //call interrupt set up function
    initSPI(); //call SPI set up function

    while(1)
    {

    }
}

void initPorts(void)
{
    DDRB = 0b00101100; //set SPI pins as outputs, unused pins as inputs
    PORTB = 0b11010011; //pull unused pins high
    DDRD = 0x00; //rotary encoder pins as inputs
    PORTD = 0x00; //pull ups off
}

void initExtInt(void)
{
    sei(); //global interrupt enable
    PCICR = 0x04; //enable Port D pin change interrupts
    PCMSK2 = 0xFF; //enable pin change interrupt on all Port D pins
}

void initSPI(void)
{
    SPCR = 0b01010001; //SPI interrupt disabled, SPI enabled, MSB trasmitted first, 
                        //master, rising edge triggered, sample then set up, fosc/8
    SPSR = SPSR | 0x01; //2x clock speed for fosc/8
}

ISR(PCINT2_vect)
{
    unsigned char reg = PCMSK2; //read pin change mask register into intermediate register
    unsigned char send;

    //laser x - left
    if(((reg & 0x80) > 0) && ((PIND & 0x40) > 0)) 
    {
        send = LASER_X_L;
    }

    //laser x - right
    else if(((reg & 0x40) > 0) && ((PIND & 0x80) > 0)) 
    {
        send = LASER_X_R;
    }

    //laser y - down
    else if(((reg & 0x20) > 0) && ((PIND & 0x10) > 0)) 
    {
        send = LASER_Y_D;
    }

    //laser y - up
    else if(((reg & 0x10) > 0) && ((PIND & 0x20) > 0)) 
    {
        send = LASER_Y_U;
    }

    //mirror x - left
    else if(((reg & 0x08) > 0) && ((PIND & 0x04) > 0)) 
    {
        send = MIRROR_X_L;
    }

    //mirror x - right
    else if(((reg & 0x04) > 0) && ((PIND & 0x08) > 0)) 
    {
        send = MIRROR_X_R;
    }

    //mirror y - down
    else if(((reg & 0x02) > 0) && ((PIND & 0x01) > 0)) 
    {
        send = MIRROR_Y_D;
    }

    //mirror y - up
    else if(((reg & 0x01) > 0) && ((PIND & 0x02) > 0)) 
    {
        send = MIRROR_Y_U; 
    }
    else
    {
        send = NOTHING;
    }

    if(send != NOTHING)
    {
        SPDR = send; //start transmission
    }   
}
    
pregunta Matt Young

1 respuesta

1

Finalmente encontré la solución a este problema.

Primero, la función de configuración SPI necesitaba ajuste.

void initSPI(void)
{
PRR = 0b11111011; //turn power saving on for all peripherals other than SPI
SPCR = 0b11111001; //SPI interrupt enabled, SPI enabled, MSB trasmitted last, 
                    //master, falling edge triggered, set up then sample, fosc/8
SPSR = 0x01; //2x clock speed for fosc/8
}

Además, el procesador no maneja el pin! SS en modo maestro. Debe establecerse en un nivel bajo al inicio de la transmisión y luego volver a ser alto manualmente.

if(send != NOTHING)
{
    PORTB =  PORTB & 0b11111011;
    SPDR = send; //start transmission
    while(!(SPSR & (1<<SPIF))); //wait for transmission to finish
    PORTB =  PORTB & 0b11111111;
}
    
respondido por el Matt Young

Lea otras preguntas en las etiquetas