Wpis z mikrobloga

#stm32, #elektronika, #jezykc, #programowanie
Cześć, n00b level over 9000 here, więc proszę o wyrozumiałość.

Piszę program, który ma w odpowiednim czasie ustawiać 1 lub 0 na wybranym pinie według określonej w postaci struktury sekwencji. Wykorzystuję do tego cztery kanały TIM1 skonfigurowane jako Output Compare. Licznik liczy z częstotliwością 20 kHz i jest resetowany co sekundę. Co każdą sekundę sekwencja ma się powtarzać. Niestety u mnie wykonuje się tylko raz i nie wiem co skopałem... Będę wdzięczny za pomoc!( ͡º ͜ʖ͡º)

Dokładnie wygląda to tak, że w pierwszej sekundzie po zresetowaniu mikrokontrolera (STM32F103RB) sekwencja wykonuje się prawidłowo (tak to wygląda na oko - sprawdzę analizatorem stanów logicznych rano), a potem zamiast 6 zmian w kolejnych sekundach wykonują się tylko dwie (nie jestem w stanie stwierdzić które).

Poniżej pasty, w spoilerze fragmenty kodu:
http://pastebin.com/S8wQgB3J
http://pastebin.com/MXygPQUh



struct output
{
GPIO_TypeDef* port;
uint16_t pin;
int start;
int duration;
};

struct output outputs[n];

volatile int counter_even = 2;
volatile int counter_odd = 3;

void InitializeOutputs(void)
{
outputs[0].port = GPIOA; // każdy z poniższych elementów ma za zadanie mrygnąć diodką (docelowo będzie to zmienione)
outputs[0].pin = GPIO_Pin_5;
outputs[0].start = 200; // after 10 ms
outputs[0].duration = 200; // for 10 ms

outputs[1].port = GPIOA;
outputs[1].pin = GPIO_Pin_5;
outputs[1].start = 3000; // after 150 ms
outputs[1].duration = 150; // for 7,5 ms

[...]

outputs[5].port = GPIOA;
outputs[5].pin = GPIO_Pin_5;
outputs[5].start = 9000; // after 450 ms
outputs[5].duration = 250; // for 12,5 ms
}

// initial match value for CCRx
oc.TIM_Pulse = outputs[0].start;
TIM_OC1Init(TIM1, &oc);

oc.TIM_Pulse = outputs[0].start + outputs[0].duration;
TIM_OC2Init(TIM1, &oc);

oc.TIM_Pulse = outputs[1].start;
TIM_OC3Init(TIM1, &oc);

oc.TIM_Pulse = outputs[1].start + outputs[1].duration;
TIM_OC4Init(TIM1, &oc);


!void TIM1_CC_IRQHandler()
{
extern volatile int counter_even, counter_odd;
extern struct output outputs[6];
volatile int shift_even = 0;
volatile int shift_odd = 0;

// run through the interrupt sources looking for a hit
if(TIM_GetITStatus(TIM1, TIM_IT_CC1) != RESET) // this if condition is setting the time at which the periferal with even number will go HIGH
{
GPIO_SetBits(outputs[counter_even - 2].port, outputs[counter_even - 2].pin);

TIM_ClearITPendingBit(TIM1, TIM_IT_CC1);
TIM_SetCompare1(TIM1, outputs[counter_even].start);
}

if(TIM_GetITStatus(TIM1, TIM_IT_CC2) != RESET) // this if condition is setting the time at which the periferal with even number will go LOW
{
GPIO_ResetBits(outputs[0].port, outputs[0].pin);

TIM_ClearITPendingBit(TIM1, TIM_IT_CC2);
TIM_SetCompare2(TIM1, outputs[counter_even].start + outputs[counter_even].duration);

shift_even = 1;
}

if(shift_even)
{
if(counter_even + 2 <= 6)
counter_even = counter_even + 2;
else
counter_even = 2;
}

if(TIM_GetITStatus(TIM1, TIM_IT_CC3) != RESET) // this if condition is setting the time at which the periferal with odd number will go HIGH
{
GPIO_SetBits(outputs[counter_odd - 2].port, outputs[counter_odd - 2].pin);

TIM_ClearITPendingBit(TIM1, TIM_IT_CC3);
TIM_SetCompare3(TIM1, outputs[counter_odd].start);
}

if(TIM_GetITStatus(TIM1, TIM_IT_CC4) != RESET) // this if condition is setting the time at which the periferal with odd number will go LOW
{
GPIO_ResetBits(outputs[counter_odd - 2].port, outputs[counter_odd - 2].pin);

TIM_ClearITPendingBit(TIM1, TIM_IT_CC4);
TIM_SetCompare4(TIM1, outputs[counter_odd].start + outputs[counter_odd].duration);

shift_odd = 1;
}

if(shift_odd)
{
if(counter_odd + 2 <= 6)
counter_odd = counter_odd + 2;
else
counter_odd = 3;
}
}

void TIM2_IRQHandler()
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET)
{
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);

if (GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_15))
GPIO_ResetBits(GPIOA, GPIO_Pin_15);
else
{
// reset counter on TIM1
TIM_SetCounter(TIM1, 0);
GPIO_SetBits(GPIOA, GPIO_Pin_15);
}
}
}
  • 8
  • Odpowiedz
  • Otrzymuj powiadomienia
    o nowych komentarzach

@Ramen: Nie, nie, zerknij na drugą pastę - ISR dla TIM2 wygląda tak:

void TIM2_IRQHandler()
{
if (TIM_GetITStatus(TIM2, TIM_IT_Update) ==
  • Odpowiedz
Niestety u mnie wykonuje się tylko raz i nie wiem co skopałem... Będę wdzięczny za pomoc!( ͡º ͜ʖ͡º)


@DonPablo: nic nie skopałeś tylko wziąłeś pewnie gotowca, który działa prawidłowo na TIM2-TIM7.
Tim1 o ile mnie pamięć nie myli ma domyślnie wyłączoną opcję reload albo włączoną oneshoot czy jakoś tak. Ja też się z tym problemem borykałem i dopiero ktoś o tym wspomniał na elektrodzie. Generalnie
  • Odpowiedz
@piastun: Haha, byłoby super, gdybym dał radę znaleźć gotowca do takiego czegoś - pisałem od początku do końca samodzielnie :P
Jestem na 99% pewien, że to błąd w softwarze, dokładnie w handlerze TIM1. Dopiero się uczę debuggowania, breakpointów i watchpointów, więc może do wieczora to naprawię, ale zdecydowanie wolałbym szybciej...
Tak to wygląda obecnie: https://drive.google.com/open?id=0BxWL4lVvaBC2bUtwTWZvck9KM0gycWdtU0RUZVNrcG1KRUR3
  • Odpowiedz
@DonPablo: sprawdzałeś, czy na tim2 wykonuje się to cyklicznie?
Zacznij od tego, jeżeli na tim2 bedzie działac ok a chcesz koniecznie robić to na tim1 to musisz doczytać o tym co pisałem wcześniej.
  • Odpowiedz