1

I have a cascade of 4 8x8 matrices working via max7219. I use stm32 f103 for send commands to the cascade. For some reason when I send CommandN, CommandN-1 performs.

Here's my code

int main(void)
{
    clockInit();
    SysTick_Init(72000000);
    initSwdOnlyDebugging();
    initPortAClock();
    initAltFunctionsClock();
    initSpi1();

    for (int i = 0; i < 4; ++i)
    {
        sendData(OperationCode::OP_DISPLAYTEST, 0x00);
    }

    ...
}

void sendData(uint8_t address, uint8_t data)
{
    GPIOA->BSRR = 1 << 4; // CS SET (PA4)
    while(!(READ_BIT(SPI1->SR, SPI_SR_TXE) == (SPI_SR_TXE))) {}

    SPI1->DR = address;
    while(!(READ_BIT(SPI1->SR, SPI_SR_RXNE) == (SPI_SR_RXNE))) {}
    (void) SPI1->DR;
    while(!(READ_BIT(SPI1->SR, SPI_SR_TXE) == (SPI_SR_TXE))) {}
    SPI1->DR = data;

    while(!(READ_BIT(SPI1->SR, SPI_SR_RXNE) == (SPI_SR_RXNE))) {}
    (void) SPI1->DR;

    GPIOA->BSRR = 1 << 4 << 16U;  // CS RESET (PA4)
}

enum OperationCode: uint8_t
{
    OP_DECODEMODE = 9,  ///< MAX72xx opcode for DECODE MODE
    OP_INTENSITY = 10,  ///< MAX72xx opcode for SET INTENSITY
    OP_SCANLIMIT = 11,  ///< MAX72xx opcode for SCAN LIMIT
    OP_SHUTDOWN = 12,   ///< MAX72xx opcode for SHUT DOWN
    OP_DISPLAYTEST = 15 ///< MAX72xx opcode for DISPLAY TEST
};

int clockInit(void)

{
    // RCC - reset and clock control, CR - Clock control register
    SET_BIT(RCC->CR, RCC_CR_HSEON); //Enable HSE clock

    while(READ_BIT(RCC->CR, RCC_CR_HSERDY) == RESET); //wait until HSE ready

    //Configuring of PLL (HSE crystal frequency is 8MHz)
    // SYSCLK = 72 МГц, USB = 48 МГц, PCLK1 = 36 МГц, PCLK2 = 72 МГц,  ADC = 12 МГц
    RCC->CFGR |= RCC_CFGR_PLLMULL9 //Bits 21:18, 0111: PLL input clock x 9
            | RCC_CFGR_PLLSRC; //Enable PLL as a source of HSE

    RCC->CR |= RCC_CR_PLLON; //Run PLL

    while(!(RCC->CR & RCC_CR_PLLRDY));
    CLEAR_BIT(FLASH->ACR, FLASH_ACR_PRFTBE);
    FLASH->ACR |= FLASH_ACR_PRFTBE;

    // 2 cycles of Flash wait because 48 MHz < SYSCLK ≤ 72 MHz
    FLASH->ACR &= ~FLASH_ACR_LATENCY_2;
    FLASH->ACR |= FLASH_ACR_LATENCY_2;

    RCC->CFGR |= RCC_CFGR_PPRE2_DIV1 //APB2/1
            | RCC_CFGR_PPRE1_DIV2 //APB1/2
            | RCC_CFGR_HPRE_DIV1; //AHB/1

    RCC->CFGR |= RCC_CFGR_SW_PLL;

    while((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_1);

    RCC->CR &= ~RCC_CR_HSION;

    return 0;
}

void initSpi1(void)
{
    auto reg = GPIOA->CRL;
    reg &= ~(GPIO_CRL_CNF4 | GPIO_CRL_MODE4 | GPIO_CRL_CNF5 | GPIO_CRL_MODE5 | GPIO_CRL_CNF6 | GPIO_CRL_MODE6 | GPIO_CRL_CNF7 | GPIO_CRL_MODE7);
    GPIOA->CRL = reg;

    GPIOA->CRL   |=  GPIO_CRL_MODE7;  // output 50 MHz
    GPIOA->CRL   &= ~GPIO_CRL_CNF7;   // Push-Pull
    GPIOA->CRL   |=  GPIO_CRL_CNF7_1; // alternative function push-pull

    GPIOA->CRL   &= ~GPIO_CRL_MODE6;  // Input
    GPIOA->CRL   |=  GPIO_CRL_CNF6_1; // with pull-up / pull-down
    GPIOA->BSRR   =  GPIO_BSRR_BS6;   // Set bit 6 High

    GPIOA->CRL   |=  GPIO_CRL_MODE5;  // output 50 MHz
    GPIOA->CRL   |=  GPIO_CRL_CNF5_1; // alternative function push-pull

    GPIOA->CRL   |=  GPIO_CRL_MODE4;  // output 50 MHz
    GPIOA->CRL   &= ~GPIO_CRL_CNF4;   // Push-Pull General Purpose
    GPIOA->BSRR   =  GPIO_BSRR_BS4;   // Set bit 4 High

    SPI1->CR1 = 0x0000; // reset SPI configuration registers
    SPI1->CR2 = 0x0000; // reset SPI configuration registers

    RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; // enable spi clock
    SPI1->CR1   &= ~SPI_CR1_SPE; // disable SPI before configuring
    SPI1->CR1 = 0 << SPI_CR1_DFF_Pos    // 8 bit Data frame format
            | 0 << SPI_CR1_LSBFIRST_Pos //  MSB transferred first
            | SPI_CR1_SSM               //Software SS
            | SPI_CR1_SSI               // NSS (CS) pin is high
            | SPI_CR1_BR_0 | SPI_CR1_BR_1  //Baud: F_PCLK/16
            | SPI_CR1_MSTR // Master mode
            | 0 << SPI_CR1_CPOL_Pos // Clock polarity
            | 0 << SPI_CR1_CPHA_Pos;  // Clock phase

    SPI1->CR1 |= SPI_CR1_SPE; // Enable SPI
}

void initPortAClock()
{
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
}
void initSwdOnlyDebugging()
{
    AFIO->MAPR |= AFIO_MAPR_SWJ_CFG_JTAGDISABLE; // JTAG is disabled
}

void initAltFunctionsClock()
{
    RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;
}

After the loop

for (int i = 0; i < 4; ++i)
{
    sendData(OperationCode::OP_DISPLAYTEST, 0x00);
}

finishes I have the first 3 matrices turned off, not all 4.

amplifier
  • 1,793
  • 1
  • 21
  • 55
  • Both of your loops do `sendData(OperationCode::OP_DISPLAYTEST, 0x00);` Is this intentional? – pmacfarlane Mar 02 '23 at 23:09
  • It is the same loop. I just type it again to highlight – amplifier Mar 03 '23 at 06:38
  • What happens if you send 5 commands? – pmacfarlane Mar 03 '23 at 08:04
  • @pmacfarlane In this case all 4 matrices are turned off as expected. The same think for another commands. If I draw 8 rows, then first command doesn't do anything. 2nd command causes drawing of 1st row (that should have been drawn right after the 1st command ends SPI transmission) – amplifier Mar 03 '23 at 09:07

1 Answers1

1

There are 2 issues:

  1. CS low and high were confused
  2. There wasn't waiting for data transfer completion

The correct version:

void sendData(uint8_t address, uint8_t data)
{
    GPIOA->BSRR = GPIO_BSRR_BR4; // CS LOW
    while(!(READ_BIT(SPI1->SR, SPI_SR_TXE) == (SPI_SR_TXE))) {}

    SPI1->DR = address;
    while(!(READ_BIT(SPI1->SR, SPI_SR_RXNE) == (SPI_SR_RXNE))) {}
    (void) SPI1->DR;
    while(!(READ_BIT(SPI1->SR, SPI_SR_TXE) == (SPI_SR_TXE))) {}
    SPI1->DR = data;

    while(!(READ_BIT(SPI1->SR, SPI_SR_RXNE) == (SPI_SR_RXNE))) {}
    (void) SPI1->DR;
    while(SPI1->SR&SPI_SR_BSY) {}
    GPIOA->BSRR = GPIO_BSRR_BS4;  // CS HIGH
}
amplifier
  • 1,793
  • 1
  • 21
  • 55