Cómo enviar un búfer con spi

0

Uso un atmega32 y quiero usar el bus SPI. Tengo el controlador Adafruit 24 canales, 12 bits pwm led. Utilizo un búfer para establecer el pwm para un canal determinado.

¿La pregunta es cómo enviar todo el búfer a través de SPI?

Mi código:

/*
lat = ss
dat = mosi
clk = clock
oe = miso is not used because it is one directional
*/

uint16_t *pwmbuffer;
int numdriver = 1;

void tlc5947(uint8_t n){
    pwmbuffer = (uint16_t *)calloc(2, 24 * n);
    /* Set MOSI and SCK output, all others input */
    DDRB = (1 << dat)|(1 << clk)|(1 << lat);
    /* Enable SPI, Master, set clock rate fck/16 */
    SPCR = (1 << SPE)|(1 << MSTR)|(1 << SPR0);
}

void write(){
    /* Start transmission */
    SPDR = pwmbuffer; // Here is the problem, I don't know how to do this

    /* Wait for transmission complete */
    while(!(SPSR & (1<<SPIF)));
}

void setPWM(uint8_t chan, uint16_t pwm){
    if (pwm > 4095){
        pwm = 4095;
    }
    if (chan > 24 * numdrivers){
        return;
    }
    pwmbuffer[chan] = pwm;
}

int main(){
    // This is not my real code but a simplified version of it
    tlc5947(numdriver);
    while(1){
        setPWM(4, 2000);
        write();
        _delay_ms(5000);
        setPWM(4, 100);
        _delay_ms(5000);
    }
}

Gracias de antemano

    
pregunta Daan Mouha

2 respuestas

2

Deberá seleccionar el esclavo mediante la selección de SlaveSelect (¿el 'lat' bit?), luego haga un bucle, enviando el búfer de 8 bits a la vez, escribiendo a SPDR y esperando que se complete cada byte. Entonces deja de afirmar SS y listo. No hay manera más eficiente que esa.

Lo más probable es que se afirmará SS estableciéndolo en BAJO.

Los microcontroladores más potentes (¿supongo que está utilizando un AVR de 8 bits?) podrán enviar más de 8 bits a la vez. Pero el AVR está limitado a transferencias de 8 bits.

    
respondido por el John Honniball
0

Publico esta respuesta para quienes no saben cómo hacerlo en el código.

// The array pwmbuffer is 16 bits wide for each element. 
uint16_t pwmbuffer[24];  // Another function is used to fill this array. This will not be handled in this section.

// I use hardware SPI off an Atmega32 chip to transmit 12 bits with 24 channels.
void write(){
    uint16_t tempbuffer;

    // Make Slave Select low to address the device.
    PORTB &= ~(1<<lat); // lat is the slave select.

    for(int i = 0; i <= 23; i+=2){
        tempbuffer = pwmbuffer[i];

        //Now to send 12 bits data, one need to send first byte.
        SPDR = (uint8_t) (tempbuffer[i] >> 8);
        // Wait until every bit has been transmitted.
        while(!(SPSR & (1 << SPIF)));

        tempbuffer = pwmbuffer[i-1];

        /* Now one need the last 4 bits of the 12 bit data. These bits are the first 4
        bits of the second 8 bits of the 16 bits. The problem is that SPI needs 8 bits
        to transmit. To solve this problem one uses the first 4 bits of the next data
        block and or it together. So one become 8 bit. Remember that the 4 bits of the
        second data block becomes last. So one get 8 + (4+4) + 8 to send, the 4 last bits of the 16 bit data block will not be used. I use a mask so that only the 4 bits needed
        will be normal, the rest of the 16 bits will become 0.*/
        SPDR = ((uint8_t) (pwmbuffer[i] & 0x00F0)) | ((uint8_t) ((pwmbuffer[i-1] >> 12) & 0x000F));
        while(!(SPSR & (1 << SPIF)));

        // Now one can send the 8 remainder bits of the 12 bit data of the second data block.
        SPDR = (uint8_t) (tempbuffer[i-1] >> 4);
        while(!(SPSR & (1 << SPIF)));
    }

    // Make Slave Select high, to de-address the device.
    PORTB |= (1<<lat);
}

Espero que esto sea útil.

    
respondido por el Daan Mouha

Lea otras preguntas en las etiquetas