Matriz de LED 8x8 con MAX7219 - Control con software SPI

0

Actualmente estoy intentando que funcione una matriz de 8x8 LED, que está controlada por un MAX7219 IC. El chip es compatible con SPI con DIN , CS y CLK pines. Intenté controlar el chip a través del software SPI con un STM32F103 . Este es mi código:

#include "stm32f10x_gpio.h"

#define CS 4
#define SCK 5
#define MOSI 7

void delay(long cycles){
    while(cycles > 0)
        cycles--;
}

void initSPI(){
    RCC->APB2ENR |= (1<<2); //Enable Port A clock
    GPIOA->CRL |= (0x3<<(4*CS)); //General PP & 50MHz speed for PA4 (CS)
    GPIOA->CRL |= (0x3<<(4*SCK)); //General PP & 50MHz speed for PA5 (SCK)
    GPIOA->CRL |= (0x3<<(4*MOSI)); //General PP & 50MHz speed for PA7 (MOSI)
}

void transmitData(uint16_t reg, uint16_t data){
    uint16_t serialData = (reg << 8) | (data & 0x00FF); //Last Bit First
    GPIOA->ODR &=~(1<<SCK); //Turn SCK low
    GPIOA->ODR &=~(1<<MOSI); //Turn MOSI low
    GPIOA->ODR &=~(1<<CS); //Turn CS low
    delay(10);
    for(int i = 0; i < 16; i++){
        if((serialData >> (15-i)) & 0x0001){ //Bit is '1'
            GPIOA->ODR |= (1<<MOSI); //Turn MOSI high
        } else{
            GPIOA->ODR &=~(1<<MOSI); //Turn MOSI low
        }
        delay(10);
        GPIOA->ODR |= (1<<SCK); //Turn SCK high
        delay(10);
        GPIOA->ODR &=~(1<<MOSI); //Turn MOSI Low
        if(i == 15){
            GPIOA->ODR |= (1<<CS); //Turn CS high
        }
        GPIOA->ODR &=~(1<<SCK); //Turn SCK low
    }

    delay(10);
    GPIOA->ODR |= (1<<SCK); //Turn SCK high
    GPIOA->ODR &=~(1<<CS); //Turn CS low
    delay(10);
    GPIOA->ODR |= (1<<CS); //Turn CS high
    delay(50);
}

void initMAX7219(){
    transmitData(0x0B,0x07); //Scan Limit
    delay(50000);
    transmitData(0x09,0x00); //Decode Mode
    delay(50000);
    transmitData(0x0C,0x01); //Shutdown Mode
    delay(50000);
    transmitData(0x0F,0x00); //Display Test
    delay(50000);
    transmitData(0x01,0x01); //Display '1'
    delay(50000);
}

int main(void)
{
    initSPI();
    initMAX7219();
    while(1){
        ;
    }
}

Y así es como se ven los estados de los pines, capturados con un analizador lógico:

Aunquecreoquehicetodocorrectamente(elestadodebitsdelDINpinsetransfiereenelflancoascendentedeCLK,los16bitscompletossedesplazanenelbordeascendentedeCS,quedeberíaaparecerapartirdel16bordeascendentedeCLK)nofunciona.Eltiempomáslargoes100nsquedebecumplirse.Cualquierayudaesmuyapreciada.

Editar:AsíescomoseveelPCB:

    
pregunta binaryBigInt

2 respuestas

1

Intente reemplazar su función transmitData () de la siguiente manera:

// Assume CS=1, to start. Leave with CS=1, as well.
void transmitData( uint16_t reg, uint16_t data ) {
    transmitByte( reg );
    transmitByte( data );
    GPIOA->ODR &= ~( 1 << CS );
    delay(10);
    GPIOA->ODR |= (1 << CS );
}

// Assume SCK=1, to start. Leave with SCK=1, as well.
// (MOSI is left in the last state of the data bit.)
void transmitByte( uint16_t data ) {
    for ( uint16_t m= 0x80; m != 0; ) {
        delay(10);
        GPIOA->ODR &= ~( 1 << SCK );
        if ( (data & m) == 0 ) GPIOA->ODR &= ~( 1 << MOSI );
        else GPIOA->ODR |= ( 1 << MOSI );
        m >>= 1;
        delay(10);
        GPIOA->ODR |= ( 1 << SCK );
    }
}

Ahora, no tengo un compilador para verificar errores de escritura estúpidos u olvidarme de declarar una variable necesaria. Pero debería transmitir la idea, de todos modos.

He creado una función intermedia para transmitir un byte, ya que la comunicación parece romperse de esta manera. La función transmitByte () maneja la transmisión de un byte. Cada paquete de envío al MAX7219 requiere dos bytes: uno para el registro y otro para los datos utilizados para modificar ese valor de registro.

Puedes cambiar ese uint16_t por un uint8_t, si tienes algo disponible, en transmitByte (). No podría decir si tuviste una (aunque espero que la tengas)

El código que escribí supone que las líneas CLK y LOAD (tu SCK y CS) son todas '1' para comenzar. Así que necesitarías inicializarlos de acuerdo con este nuevo plan. Algo como esto:

void initMAX7219( ) {
    GPIOA->ODR |= ( 1 << SCK );
    GPIOA->ODR |= (1 << CS );
    transmitData( 0x0B, 0x07 ); //Scan Limit
    delay( 50000 );
    transmitData( 0x09, 0x00 ); //Decode Mode
    delay( 50000 );
    transmitData( 0x0C, 0x01 ); //Shutdown Mode
    delay( 50000 );
    transmitData( 0x0F, 0x00 ); //Display Test
    delay( 50000 );
    transmitData( 0x0A, 0x0F ); //Intensity to max value
    delay( 50000 );
    transmitData( 0x01, 0x01 ); //Display '1'
    delay( 50000 );
}

¿Nota que he agregado un cambio de registro de intensidad?

Use lo anterior para considerar su código, o pruébelo. Una cosa que creo que es importante es que puede haber perdido el ajuste del valor del registro de intensidad. Entonces quizás solo cambie su código en ese punto y vea si lo lleva allí. Pero, si no es así, pruebe los cambios anteriores y vea si eso hace una diferencia.

    
respondido por el jonk
0

fue resuelto?

Tengo un ejemplo de esto

//OPTIONS
#define SCANLIMIT 7
#define INTENSITY_HIGH 12
#define INTENSITY_MED 7
#define INTENSITY_LOW 3
#define DP 0x80
#define MINUS 0x0a
#define BLANK 0x0f
#define DECODEMODE 0x00

//OPCODES
#define OP_NOOP   0x00
#define OP_DIGIT0 1
#define OP_DIGIT1 2
#define OP_DIGIT2 3
#define OP_DIGIT3 4
#define OP_DIGIT4 5
#define OP_DIGIT5 6
#define OP_DIGIT6 7
#define OP_DIGIT7 8
#define OP_DECODEMODE  9
#define OP_INTENSITY   10
#define OP_SCANLIMIT   11
#define OP_SHUTDOWN    12
#define OP_DISPLAYTEST 15


MAX7219_SPISend(OP_DISPLAYTEST,0);
MAX7219_SPISend(OP_SHUTDOWN,1);
MAX7219_SPISend(OP_INTENSITY, INTENSITY_LOW);       
MAX7219_SPISend(OP_SCANLIMIT, SCANLIMIT);
MAX7219_SPISend(OP_DECODEMODE, DECODEMODE);

¿Ayuda?

    
respondido por el Erisson Siqueira

Lea otras preguntas en las etiquetas