Forum: Mikrocontroller und Digitale Elektronik STM32F3 MAX7219 SPI


von Schweigert V. (schweigert_v)


Angehängte Dateien:

Lesenswert?

ich versuche gerade, eine 7 Segment Indicator (siehe Bild), die von 
einem MAX7219 gesteuert wird, mit einem STM32F303 via Software SPI 
anzusteuern.
Aber klappt etwas nicht!
1
  
2
/**
3
 ******************************************************************************
4
 * @file    main.c
5
 * @author  Ac6
6
 * @version V1.0
7
 * @date    01-December-2013
8
 * @brief   Default main function.
9
 ******************************************************************************
10
 */
11
12
#include "stm32f30x.h"
13
#include "stm32f30x_gpio.h"
14
#include "stm32f30x_rcc.h"
15
#include "stm32f30x_spi.h"
16
17
#define SCK_Pin  GPIO_Pin_10
18
#define SCK_Pin_Port GPIOC
19
20
#define MOSI_Pin GPIO_Pin_12
21
#define MOSI_Pin_Port GPIOC
22
23
#define SS_Pin  GPIO_Pin_2
24
#define SS_Pin_Port GPIOD
25
26
#define cs_set() SS_Pin_Port->BRR = SS_Pin;
27
#define cs_reset() SS_Pin_Port->BSRR = SS_Pin;
28
29
//OPTIONS
30
#define SCANLIMIT 7
31
#define INTENSITY_HIGH 12
32
#define INTENSITY_MED 7
33
#define INTENSITY_LOW 3
34
#define DP 0x80
35
#define MINUS 0x0a
36
#define BLANK 0x0f
37
#define DECODEMODE 0xff
38
39
//OPCODES
40
#define OP_NOOP   0
41
#define OP_DIGIT0 1
42
#define OP_DIGIT1 2
43
#define OP_DIGIT2 3
44
#define OP_DIGIT3 4
45
#define OP_DIGIT4 5
46
#define OP_DIGIT5 6
47
#define OP_DIGIT6 7
48
#define OP_DIGIT7 8
49
#define OP_DECODEMODE  9
50
#define OP_INTENSITY   10
51
#define OP_SCANLIMIT   11
52
#define OP_SHUTDOWN    12
53
#define OP_DISPLAYTEST 15
54
55
void SPISend(uint8_t addr, uint8_t data) {
56
  cs_set()
57
  ;
58
  SPI_I2S_SendData16(SPI3, (((uint16_t) addr << 8) + data));
59
  cs_reset()
60
  ;
61
62
}
63
64
void SPIInit(void) {
65
66
  SPI_InitTypeDef SPIConf;
67
  SPIConf.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
68
  SPIConf.SPI_Mode = SPI_Mode_Master;
69
  SPIConf.SPI_DataSize = SPI_DataSize_8b;
70
  SPIConf.SPI_CRCPolynomial = 7;
71
  SPIConf.SPI_CPOL = SPI_CPOL_Low;
72
  SPIConf.SPI_CPHA = SPI_CPHA_1Edge;
73
  SPIConf.SPI_NSS = SPI_NSS_Soft;
74
  SPIConf.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
75
  SPIConf.SPI_FirstBit = SPI_FirstBit_MSB;
76
  SPI_Init(SPI3, &SPIConf);
77
  SPI_Cmd(SPI3, ENABLE);
78
}
79
80
void GPIOInit(void) {
81
  RCC_AHBPeriphClockCmd(
82
  RCC_AHBPeriph_GPIOC | RCC_AHBPeriph_GPIOD | RCC_APB1ENR_SPI3EN, ENABLE);
83
  GPIO_InitTypeDef PORT;
84
85
  PORT.GPIO_Pin = GPIO_Pin_10 ;
86
  PORT.GPIO_Speed = GPIO_Speed_2MHz;
87
  PORT.GPIO_Mode = GPIO_Mode_AF;
88
  GPIO_Init(GPIOC, &PORT);
89
90
  PORT.GPIO_Pin = GPIO_Pin_12;
91
  PORT.GPIO_Speed = GPIO_Speed_2MHz;
92
  PORT.GPIO_Mode = GPIO_Mode_AF;
93
  GPIO_Init(GPIOC, &PORT);
94
95
  PORT.GPIO_Pin = GPIO_Pin_2;
96
  PORT.GPIO_Speed = GPIO_Speed_2MHz;
97
  PORT.GPIO_Mode = GPIO_Mode_OUT;
98
  GPIO_Init(GPIOD, &PORT);
99
}
100
101
int main() {
102
  SystemInit();
103
  GPIOInit();
104
  SPIInit();
105
  for (;;) {
106
    SPISend(OP_DISPLAYTEST, 0);
107
    SPISend(OP_SHUTDOWN, 1);
108
109
110
    SPISend(OP_DECODEMODE, DECODEMODE);
111
    SPISend(OP_DIGIT0, 7 + DP);
112
    SPISend(OP_DIGIT1, 6);
113
    SPISend(OP_DIGIT2, 5 + DP);
114
    SPISend(OP_DIGIT3, 4);
115
    SPISend(OP_DIGIT4, 3 + DP);
116
    SPISend(OP_DIGIT5, 2);
117
    SPISend(OP_DIGIT6, 1 + DP);
118
    SPISend(OP_DIGIT7, 0);
119
  }
120
}


MOD: bitte Bedienungsanleitung ab "Wichtige Regeln - erst lesen, dann 
posten!" lesen und [c] Tags verwenden.

: Bearbeitet durch Moderator
von :-) (Gast)


Lesenswert?

ich benutze zwar keinen STM32F...

aber den MAX7219 an PIC Controllern in Assembler.
Damit er da funktioniert muss ich den Serial Port am PIC so einstellen, 
dass mit steigender Clockflanke gesendet wird und die Clockpolarität 
auf: Clock Idle State high.

Bei dir dürfte das CPOL (Clock Polarity) und CPHA (Clock Phase) sein.

von Jim M. (turboj)


Lesenswert?

Bei dem Code sehe ich nicht wie T_CSW oder T_CSS eingehalten werden 
soll.

Logic high input voltage von mindestens 3,5V sprechen auch eher gegen 
einen STM32, der nur 3,3V VCC verträgt. Da müsste ein Pegelwandler 
zwischen, falls der STM keine mit 5V befeuerten I/Os hat.

> via Software SPI

Ich sehe da nur Hardware SPI Zugriffe.

von Daniel B. (dbuergin)


Lesenswert?

Vielleicht hilft Dir dieser Thread: 
Beitrag "STM32F411 --> SPI --> MAX7219"

von SchaumSchläger (Gast)


Lesenswert?

Jim M. schrieb:
> Ich sehe da nur Hardware SPI Zugriffe.

Also alles in allem betrachtet eine rundum durchdachte Lösung.

von OhWeia (Gast)


Lesenswert?

Das habe ich vor ein paar Tagen im Netz gefunden. Soft-SPI und ging auf 
anhieb.
1
void max7219_brightness(char brightness) {
2
  brightness &= 0x0f;                                 // mask off extra bits
3
  max7219_write_reg(REG_INTENSITY, brightness);           // set brightness
4
5
}
6
7
void max7219_write_reg(unsigned char reg_number, unsigned char dataout) {
8
  gpio_clear(LOAD_PORT, LOAD_PIN);
9
  max7219_send_byte(reg_number);                       // write register number to MAX7219
10
  max7219_send_byte(dataout);                          // write data to MAX7219
11
  gpio_set(LOAD_PORT, LOAD_PIN);
12
}
13
14
void max7219_send_byte(unsigned char dataout) {
15
  char i;
16
  for (i=8; i>0; i--) {
17
    unsigned char mask = 1 << (i - 1);                // calculate bitmask
18
    gpio_clear(CLK_PORT, CLK_PIN);
19
    if (dataout & mask)                               // output one data bit
20
      gpio_set(DATA_PORT, DATA_PIN);
21
    else                                              //  or
22
      gpio_clear(DATA_PORT, DATA_PIN);
23
    gpio_set(CLK_PORT, CLK_PIN);
24
  }
25
}
26
27
void init_max7219(void) {
28
  rcc_periph_clock_enable(RCC_GPIOB); // TODO: RCC_xxxx aus PORT erzeugen
29
30
    
31
    gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
32
    gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
33
    gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO15);
34
35
  max7219_write_reg(REG_SCAN_LIMIT, 7);                   // set up to scan all eight digits
36
  max7219_write_reg(REG_DECODE, 0x00);                    // set to "no decode" for all digits
37
  max7219_write_reg(REG_SHUTDOWN, 1);                     // put MAX7219 into "normal" mode
38
  max7219_write_reg(REG_DISPLAY_TEST, 0);                 // put MAX7219 into "normal" mode
39
  
40
  max7219_brightness(0x00);
41
  
42
}

von OhWeia (Gast)


Lesenswert?

Header vergessen.
1
#define DATA_PORT       GPIOB                           // assume "DATA" is on PA7
2
#define DATA_PIN        GPIO15
3
#define CLK_PORT        GPIOB                           // assume "CLK" is on PA5
4
#define CLK_PIN         GPIO13
5
#define LOAD_PORT       GPIOB                           // assume "LOAD (nCS)" is on PA6
6
#define LOAD_PIN     GPIO12
7
8
#define REG_NOP           0x00                        // Nop for daisy chaining
9
#define REG_DIGIT0   0x01
10
#define REG_DIGIT1   0x02
11
#define REG_DIGIT2   0x03
12
#define REG_DIGIT3   0x04
13
#define REG_DIGIT4   0x05
14
#define REG_DIGIT5   0x06
15
#define REG_DIGIT6   0x07
16
#define REG_DIGIT7       0x08
17
#define REG_DECODE        0x09                        // "decode mode" register
18
#define REG_INTENSITY     0x0a                        // "intensity" register
19
#define REG_SCAN_LIMIT    0x0b                        // "scan limit" register
20
#define REG_SHUTDOWN      0x0c                        // "shutdown" register
21
#define REG_DISPLAY_TEST  0x0f                        // "display test" register

von Schweigert V. (schweigert_v)


Lesenswert?

Alles klappt. In main() nicht vergessen zwei Funktion zu schreiben 
Init_SPI();Init_7219();  Dann einfach schreibt: Send_7219(1,1); erste 
Ziffer bedeutet stelle zweite genaue welche ziffer.  Quellcode:
1
#include "max7219.h"
2
#include "stm32f30x.h"
3
#include "stm32f30x_gpio.h"
4
#include "stm32f30x_rcc.h"
5
#include "stm32f30x_spi.h"
6
7
#define cs_ON() GPIO_ResetBits(GPIOD, GPIO_Pin_2);
8
#define cs_OFF() GPIO_SetBits(GPIOD, GPIO_Pin_2);
9
10
char dg = 8;
11
12
void Init_SPI(void) {
13
14
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
15
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);
16
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
17
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE);
18
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE);
19
20
  GPIO_InitTypeDef PORT;
21
  PORT.GPIO_Pin = GPIO_Pin_10; //10:SCK->CLK
22
  PORT.GPIO_Speed = GPIO_Speed_Level_1;
23
  PORT.GPIO_Mode = GPIO_Mode_AF;
24
  PORT.GPIO_OType = GPIO_OType_PP;
25
  PORT.GPIO_PuPd = GPIO_PuPd_NOPULL;
26
  GPIO_Init(GPIOC, &PORT);
27
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_6);
28
29
  PORT.GPIO_Pin = GPIO_Pin_12; // 12:MOSI->DIN
30
  PORT.GPIO_Speed = GPIO_Speed_Level_1;
31
  PORT.GPIO_Mode = GPIO_Mode_AF;
32
  PORT.GPIO_OType = GPIO_OType_PP;
33
  PORT.GPIO_PuPd = GPIO_PuPd_NOPULL;
34
  GPIO_Init(GPIOC, &PORT);
35
  GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_6);
36
37
  PORT.GPIO_Pin = GPIO_Pin_2; // SS->CS
38
  PORT.GPIO_Speed = GPIO_Speed_Level_1;
39
  PORT.GPIO_Mode = GPIO_Mode_OUT;
40
  PORT.GPIO_OType = GPIO_OType_PP;
41
  GPIO_Init(GPIOD, &PORT);
42
  GPIO_SetBits(GPIOD, GPIO_Pin_2);
43
44
45
  SPI_InitTypeDef SPIConf;
46
  SPIConf.SPI_Direction = SPI_Direction_1Line_Tx;
47
  SPIConf.SPI_Mode = SPI_Mode_Master;
48
  SPIConf.SPI_DataSize = SPI_DataSize_16b;
49
  //SPIConf.SPI_CRCPolynomial = 7;
50
  SPIConf.SPI_CPOL = SPI_CPOL_Low;
51
  SPIConf.SPI_CPHA = SPI_CPHA_1Edge;
52
  SPIConf.SPI_NSS = SPI_NSS_Soft | SPI_NSSInternalSoft_Set;
53
  SPIConf.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
54
  SPIConf.SPI_FirstBit = SPI_FirstBit_MSB;
55
  SPI_Init(SPI3, &SPIConf);
56
  SPI_Cmd(SPI3, ENABLE);
57
  SPI_NSSInternalSoftwareConfig(SPI3, SPI_NSS_Soft);
58
}
59
60
//------------------------------------------------------
61
62
void Send_7219(uint8_t rg, uint8_t dt) {
63
  cs_ON()
64
  ;
65
  while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_TXE) == RESET)
66
    ;
67
  SPI_I2S_SendData16(SPI3, (((uint16_t) rg << 8) + dt));
68
  while (SPI_I2S_GetFlagStatus(SPI3, SPI_I2S_FLAG_BSY) == SET)
69
    ;
70
  cs_OFF()
71
  ;
72
}
73
74
void Clear_7219(void) {
75
76
  Send_7219(0x01, 0x00);
77
  Send_7219(0x02, 0x00);
78
  Send_7219(0x03, 0x00);
79
  Send_7219(0x04, 0x00);
80
}
81
82
void Number_7219(volatile long n) {
83
  uint8_t ng = 0;
84
  if (n < 0) {
85
    ng = 1;
86
    n *= -1;
87
  }
88
  uint8_t i = 0;
89
  do {
90
    Send_7219(++i, n % 10);
91
    n /= 10;
92
  } while (n);
93
  if (ng) {
94
    Send_7219(i + 1, 0x0A);
95
  }
96
}
97
98
void Init_7219(void) {
99
  Send_7219(0x0F, 0x00);
100
  Send_7219(0x0C, 0x01);
101
  Send_7219(0x0B, 0x03);
102
  Send_7219(0x0A, 0x0A);
103
  Send_7219(0x09, 0xFF);
104
  Clear_7219();
105
}
106
107
void delay(uint32_t us) {
108
  volatile uint32_t nCount;
109
  RCC_ClocksTypeDef RCC_Clocks;
110
  RCC_GetClocksFreq(&RCC_Clocks);
111
  nCount = (RCC_Clocks.HCLK_Frequency / 7200) * us;
112
  for (; nCount != 0; nCount--)
113
    ;
114
}

: Bearbeitet durch Moderator
von Christian J. (Gast)


Lesenswert?

Hi,

ic bin seit 6h an dem gleichen Problem dran. Diese LED Matrizzen mit 8x8 
und nichts klappt am STM32103. Ja, es tut sich was aber nur Müll. Daten 
laufen richtig raus, am LA geprüft. Aber es reagieren immer mehrere der 
kaskadierten Matrizzen. Nicht mal nacheinander liegen die. Habe 12 in 
Reihe geschaltet. Gibt es als 4er Blocks zu kaufen. Auch eine tut es 
nicht allein.

Ist das sicher, dass der Max719 auch mit 3.3V noch "haarscharf" 
schaltet? Gibt ja auch ESP8266 Videos, wo er es tut. Wenn er es nicht 
tut verstehe ich den zufälligen Müll schon eher.

8 und 16 Bit ausprobiert, beides geht aber wohl. Das Durchschieben lasse 
ich erstmal weg, nur dass 1 Display erstmal läuft, das erste vorne.
1
   /* Die SPI einstellen: Master, 1 Line TX, 8 Bit, Mode 0 */
2
    SPI_StructInit(&SPI_InitStruct);
3
    SPI_InitStruct.SPI_Direction = SPI_Direction_1Line_Tx;
4
    SPI_InitStruct.SPI_Mode      = SPI_Mode_Master;
5
    SPI_InitStruct.SPI_DataSize  = SPI_DataSize_8b;
6
    SPI_InitStruct.SPI_CPOL      = SPI_CPOL_Low;
7
    SPI_InitStruct.SPI_CPHA      = SPI_CPHA_1Edge;
8
    SPI_InitStruct.SPI_NSS       = SPI_NSS_Soft;
9
    SPI_InitStruct.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;        // 4.5 Mhz
10
    SPI_InitStruct.SPI_FirstBit  = SPI_FirstBit_MSB;
11
12
    SPI_Init(MAX_SPI, &SPI_InitStruct);
13
    SPI_Cmd(MAX_SPI, ENABLE);
14
}
15
16
void SendCmd(uint8_t modul, uint8_t cmd, uint8_t val)
17
{
18
    if (modul > 11)
19
        return;
20
21
    CE_LOW();
22
    SPI_SendByte(cmd);
23
    SPI_SendByte(val);
24
25
//    for (int i = 0; i < modul; i++) {
26
//        SPI_SendWord(MAX7219_NOP);
27
//    }
28
29
    CE_HIGH();
30
31
}
32
33
/* Init Matrix LED */
34
void InitMatrix()
35
{
36
    int v = 0;
37
38
    /* Decode Mode ausschalten */
39
    SendCmd(v,MAX7219_DECODE_MODE,0);
40
    SendCmd(v,MAX7219_SCAN_LIMIT,7);
41
    SendCmd(v,MAX7219_BRIGHTNESS,2);
42
    SendCmd(v,MAX7219_SHUTDOWN,1);
43
    SendCmd(v,MAX7219_TEST,0);
44
45
    SendCmd(v,MAX7219_DIGIT_0,6);

von John Doe (Gast)


Lesenswert?

Christian J. schrieb:
> Ist das sicher, dass der Max719 auch mit 3.3V noch "haarscharf"
> schaltet? Gibt ja auch ESP8266 Videos, wo er es tut. Wenn er es nicht
> tut verstehe ich den zufälligen Müll schon eher.


Warum gibst Du dem Max nicht einfach eine laut Datenblatt vorgegebene 
Spannung und schaust, was passiert?

Bei mir am F446 läuft es übrigens. Heisst aber nix.

von Christian J. (Gast)


Lesenswert?

John Doe schrieb:
> Warum gibst Du dem Max nicht einfach eine laut Datenblatt vorgegebene
> Spannung und schaust, was passiert?

Weil ich die nicht auf dem Lochraster habe? Und einen 74HCT04 dazubauen 
ginge noch aber vorher Klarheit schaffen.

von Christian J. (Gast)


Angehängte Dateien:

Lesenswert?

hmm.... ein 7404 ist eingebaut, je 2 Inverter in Reihe für die 3 Kanäle 
CS, MOSI und CLK... trotzdem spielt das Teil nicht. Gibt es da noch 
einen Kniff? Daten stimmen jedenfalls. Die Muster die ich einspiele 
erscheinen in allen 4 Displays gleichzeitig und nicht nur in dem ersten.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.