Hallo, ich arbeite mich in den STM32 mit dem STM32F4Discovery (407) ein (Coocox IDE 1.7.8). Nun habe ich ein paar von den LEDs (siehe Anhang, voltage step down programmeable). Da die mit 5V laufen, hab ich noch einen 74HCT125 zwischen geschaltet (siehe Anhang). Da mein Interrupt-Ansatz zuerst nicht funktionierte, habe ich das ganze sehr banal angegangen. Bitte nicht schlagen: // STRIPE_PORT=GPIOD // STRIPE_H = GPIO_Pin_0, H da im Ruhezustand H // STRIPE_L = GPIO_PIN_1, L da im Ruhezustand L // SHORT_DELAY = 35 void writeHalf(uint8_t intensity) { int i; uint32_t j; for(i=0;i<(8-intensity);i++) { GPIO_WriteBit(STRIPE_PORT, STRIPE_H, Bit_RESET); for(j=0;j<SHORT_DELAY;j++) {} // 4µs... als Short delay noch 288 war... GPIO_WriteBit(STRIPE_PORT, STRIPE_H, Bit_SET); for(j=0;j<SHORT_DELAY;j++) {} // 4µs... } for(i=0;i<intensity;i++) { GPIO_WriteBit(STRIPE_PORT, STRIPE_L, Bit_SET); for(j=0;j<SHORT_DELAY;j++) {} // 4µs... GPIO_WriteBit(STRIPE_PORT, STRIPE_L, Bit_RESET); for(j=0;j<SHORT_DELAY;j++) {} // 4µs... } } Das ganze für 5 Leds im Hauptprogramm je LED 3 mal aufgerufen, Werte zwischen 0 und 8. Alles super soweit, bekomme die Farben die ich möchte. Also wieder ran an die Interrupt-Routine: // HSE_VALUE = (uint32_T)8000000; PLL_M = 8; SystemInit() wird als erstes in main ausgeführt. void initTimerLEDStripe() { RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); TIM_TimeBaseInitTypeDef tim4Def; NVIC_InitTypeDef nvicDef4; tim4Def.TIM_ClockDivision = TIM_CKD_DIV1; tim4Def.TIM_CounterMode = TIM_CounterMode_Up; // approx 0.6µs, da APB1 mit Teiler 4 und Multiplikator 2 = 84MHz tim4Def.TIM_Period = 4; tim4Def.TIM_Prescaler = 9; TIM_TimeBaseInit(TIM4, &tim4Def); TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE); nvicDef4.NVIC_IRQChannel = TIM4_IRQn; nvicDef4.NVIC_IRQChannelCmd = ENABLE; nvicDef4.NVIC_IRQChannelPreemptionPriority = 0x0F; nvicDef4.NVIC_IRQChannelSubPriority = 0x0F; NVIC_Init(&nvicDef4); // Do nothing for the time beeing... TIM_Cmd(TIM4, DISABLE); } Hier die Interrupt-Routine und variablen. Ich habe den Ansatz gewählt, jede Zustandsänderung in einem Array zu hinterlegen. struct ledStripeValue { BitAction action; uint16_t pin; GPIO_TypeDef* port; }; volatile struct ledStripeValue ledValues[5*3*8*2]; volatile uint32_t counter = 0; void TIM4_IRQHandler(void) { TIM_ClearITPendingBit(TIM4, TIM_IT_Update); if(counter < sizeof(ledValues)) { GPIO_WriteBit(ledValues[counter].port, ledValues[counter].pin, ledValues[counter].action); counter++; } else { counter++; if(counter > 26000) { // Latch time 3ms done... TIM_Cmd(TIM4, DISABLE); counter = 0; } } } Hauptprogramm: int main(void) { SystemInit(); init(); // TIM2 and TIM3 with 1ms interrupt, TIM2 counts uint32_t millisCounter up initTimer(); GPIO_WriteBit(STRIPE_PORT, STRIPE_H, Bit_SET); GPIO_WriteBit(STRIPE_PORT, STRIPE_L, Bit_RESET); initTimerLEDStripe(); initLEDStripe(); while(1) { setOneLedRed(); // like initLEDStripe, only setting appripriate bits to H simpleDelay(1000); // wait a second initLEDStripe(); // Clear all LEDs simpleDelay(1000); } } Es passiert nix, rein gar nix. Mit dem Debugger - dem ich hierbei nicht wirklich traue - sieht es so aus, als wenn das Hauptprogramm priorität gegenüber der Interrupt-Routine hat. Anscheinend zählt er nicht hoch. Er steht beim debuggen in der simpleDelay, der Brechpunkt in der Interrupt wird nur selten aufgerufen. Ach ja, simpleDelay: void simpleDelay(uint32_t ms) { uint32_t current = millisCounter; while( (millisCounter-current) <= ms) { } } Wenn ich so nachrechne, dann sollte es mit der Einfachmethode nicht gehen, For-Schleife wird 35 mal durchlaufen. Bei 168MHz wären das 0,2µs. Die LEDs brauchen aber angeblich 1µs. Was mache ich falsch, wo ist mein Denkfehler? Werde daraus nicht schlau. Besten Dank im voraus für jede Hilfe. Jörg
Oh, sehe gerade in der Schaltung ist der Abgriff zwischen den Widerständen zum D_in des ersten LEDs nicht zu sehen.
Wo initialisierst du denn die GPIOs? Un dann: Joerg schrieb: > TIM_Cmd(TIM4, DISABLE); Damit endet sowohl die Initialisierung als auch die IRQ Routine. So wird dein Timer aber nie gestartet, denn irgendwo sollte dann ja mal
1 | TIM_Cmd(TIM4, ENABLE); |
stehen. Und wenn du schon Timer 4 nimmst, warum nicht gleich mit den PWM Registern? Da sind die drei Kanäle schon fix und fertig und die ganze Sache läuft prima im Hintergrund. So gehts mit Kanal 2 (war die orange LED, wimre):
1 | TIM_OCInitTypeDef TIM_OCInitStructure; |
2 | TIM_OCStructInit(&TIM_OCInitStructure); |
3 | TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; |
4 | TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; |
5 | TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; |
6 | TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; |
7 | TIM_OCInitStructure.TIM_Pulse = 1050; |
8 | TIM_OC2Init(TIM4, &TIM_OCInitStructure); |
Wenn der SysTick läuft, ist Joerg schrieb: > nvicDef4.NVIC_IRQChannelPreemptionPriority = 0x0F; > nvicDef4.NVIC_IRQChannelSubPriority = 0x0F; Möglicherweise noch hinter SysTick. Gib ihm mal etwas höhere Priorität. Sollte aber trotzdem klappen.
:
Bearbeitet durch User
Hallo, erstmal vielen Dank, PWM werde ich mir mal anschauen, wenn ich den normalen Timermodus ans laufen bekomme. Bin mir noch nicht so ganz im klaren darüber, wie ich damit den Tri-State (H-M-L) abbilde. TIM4 disable ich in der initialisierung, da ich den Timer nur laufen lassen wollte, wenn ich etwas neues Anzeigen möchte. Den interrupt zu disablen würde auch reichen, das hab ich noch nicht geprüft, wie das geht. Hier die Routinen zum Füllen des Arrays, hier wird dann auch der Timer enabled.
1 | void initLEDStripe() { |
2 | for(int i=0; i<sizeof(ledValues);i+=2) { |
3 | struct ledStripeValue test; |
4 | test.pin = STRIPE_H; |
5 | test.port = GPIOD; |
6 | test.action = Bit_RESET; |
7 | ledValues[i] = test; |
8 | struct ledStripeValue test2; |
9 | test2.pin = STRIPE_H; |
10 | test2.port = GPIOD; |
11 | test2.action = Bit_SET; |
12 | ledValues[i+1] = test2; |
13 | }
|
14 | counter = 0; |
15 | TIM_Cmd(TIM4, ENABLE); |
16 | }
|
17 | |
18 | void setOneLedRed() { |
19 | for(int i=0;i<40;i+=2) { |
20 | ledValues[i].pin = STRIPE_H; |
21 | ledValues[i].action = Bit_RESET; |
22 | ledValues[i+1].pin = STRIPE_H; |
23 | ledValues[i+1].action = Bit_SET; |
24 | }
|
25 | // Rot nur 50%...
|
26 | for(int i=40;i<48;i+=2) { |
27 | ledValues[i].pin = STRIPE_L; |
28 | ledValues[i].action = Bit_SET; |
29 | ledValues[i+1].pin = STRIPE_L; |
30 | ledValues[i+1].action = Bit_RESET; |
31 | }
|
32 | for(int i=48;i<(5*8*3*2);i+=2) { |
33 | ledValues[i].pin = STRIPE_H; |
34 | ledValues[i].action = Bit_RESET; |
35 | ledValues[i+1].pin = STRIPE_H; |
36 | ledValues[i+1].action = Bit_SET; |
37 | }
|
38 | counter = 0; |
39 | TIM_Cmd(TIM4, ENABLE); |
40 | }
|
GPIOs werden in meiner init-Methode initialisiert:
1 | void init(void) { |
2 | GPIO_InitTypeDef GPIO_InitStructure; |
3 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); |
4 | GPIO_InitStructure.GPIO_Pin = LED_GN | LED_OR | LED_RD | LED_BL | STRIPE_H | STRIPE_L; |
5 | GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; |
6 | GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; |
7 | GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; |
8 | GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz; |
9 | GPIO_Init(GPIOD, &GPIO_InitStructure); |
10 | }
|
Ich werde heute Abend mal die Prioriäten ändern. Für TIM2,3,4 NVIC_IRQChannelPreemptionPriority = 0x00; Für TIM2 NVIC_IRQChannelSubPriority = 0x00; Für TIM3 NVIC_IRQChannelSubPriority = 0x08; Für TIM4 NVIC_IRQChannelSubPriority = 0x0F; Das würde dann meiner vollständigen Anwendung gerecht, in der ich TIM2 als millisekunden-Timer nutze, der recht präzise sein sollte, TIM3 wird als Überwachungs/Ausschalt-Timer genutzt und TIM4 für die Anzeige. Werde berichten, wenn es daran liegt, aber ich meine die Prioritäten auch mal angepasst zu haben, aber heute morgen im Zug habe ich dann nochmal genauer nachgelesen und bin mir nicht sicher, ob ich das gestern Abend richtig gemacht habe.
OH MANN!!! Manchmal sollte ich das zwischen meinen Ohren prüfen lassen...
1 | for(int i=0; i<sizeof(ledValues);i+=2) { |
dabei sollte das heißen:
1 | #define array_length(x) (sizeof(x)/sizeof((x)[0]))
|
2 | |
3 | for(int i=0; i<array_length(ledValues);i+=2) { |
Und schon klappt es, wenn ich alle sizeof durch array_length ersetze. Ich will da die Anzahl der Array-Elemente und nicht die bytes haben... Geh jetzt erstmal in eine Ecke und schäm mich. Danke für die Hilfe! Jörg
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.