Cannot change pointer for port in main loop (arduino uno) - Page 1
Forum section: electronics / general

author: Numex106
author_rank: Newbie
timestamp: October 14, 2021, 05:17:16 am
content: I am testing on an Arduino UNO. I want to use timer1 and interrupts to create various LED patterns. The LEDs may span multiple ports i.e PORTB and PORTD. I want to use a "volatile uint8_t*" pointer to store whether to toggle a pin on PORTB or PORTD i.e have the pointer store &PORTB or &POINTD. And then use it as necessary. However, once set, I cannot seem to be able to change the pointer in the loop.Some more details:I'm using timer1 in CTC mode (clear on compare match) and making use of both OCR1A and OCR1B interrupts.When output compare A interrupt matches, the led is turned on and a flag is set for the main loop to change leds.When output compare B interrupt matches, the led is turned off.The switch statement works and the led pins can be changed i.e next_led and current_led, however, the next_port and current_port statements are ignored in the main loop.The led pin change works when changing from case 3 to case 1 (when they are both PORTB), but when changing the next_port variable to PORTD this is completely ignored.At the very beginning of the code, if I initialize current_port and next_port with &PORTD, then just PORTD led will light up and the main loop will not change the current_port and next_port variable to &PORTB.I have tried using volatile uint16_t* for the next_port and current_port and that doesn't work, either.What am I doing wrong?Code:int red_led = 9; //PORTB 1int green_led = 10; //PORTB 2int led3 = 5; //PORTD 5volatile uint8_t current_led = 1; //port number of ledvolatile uint8_t next_led = 1;volatile uint8_t *current_port = &PORTB;volatile uint8_t *next_port = &PORTB;int counter = 0;volatile int change_led_flag = 0;volatile uint8_t led_state = 1;uint16_t ocr1a_val = 10000-1; //determines period. 16MHz clock, Prescaler=8, 10000-1 ticks = 5ms period (200Hz)uint16_t ocr1b_val = 9900-1; //determines duty cycle (99% for 10000 ticks)void setup() {pinMode(red_led, OUTPUT);pinMode(green_led, OUTPUT);pinMode(led3, OUTPUT);TCCR1A = 0;TCCR1B = 0;//set CTC modeTCCR1B |= (1<<WGM12);//set OCR1A valueOCR1A = ocr1a_val;//set OCR1B valueOCR1B = ocr1b_val;//set pre-scaler to 8TCCR1B |= (1 << CS11);//enable output compare interruptsTIMSK1 |= (1 << OCIE1A);TIMSK1 |= (1 << OCIE1B);sei();}void loop() {if(change_led_flag == 1){change_led_flag = 0;current_led = next_led; //set the current led to what was just turned oncurrent_port = next_port; //this statement doesn't do anything.switch (led_state) {case 1:led_state = 2;next_led = 2;next_port = &PORTB; //this statement doesn't do anythingbreak;case 2:led_state = 3;next_led = 5;next_port = &PORTD; //this statement doesn't do anythingbreak;case 3:led_state = 1;next_led = 1;next_port = &PORTB; //this statement doesn't do anythingbreak;} //end switch statement} //end if} //end loop()//turn on next_led and set change_led_flagISR(TIMER1_COMPA_vect){*next_port |= (1 << next_led); //turn on ledchange_led_flag = 1; //set flag to update next led}//turn off current_ledISR(TIMER1_COMPB_vect){*current_port &= ~(1 << current_led); //turn off led}

author: brucehoult
author_rank: Super Contributor
timestamp: October 14, 2021, 06:35:45 am
content: The port must be volatile because it is hardware.The pointer to the port must be volatile because it is set in your loop and read in the interrupt handler.Code:volatile uint8_t *volatile current_port = &PORTB;volatile uint8_t *volatile next_port = &PORTB;

author: abyrvalg
author_rank: Frequent Contributor
timestamp: October 14, 2021, 07:57:02 am
content: Also there will be strange effects when the interrupt is fired right between next_pin and next_port assignments. Why not do that state advance straight in the ISR? It may look like you are minimizing ISR processing time freeing it up for next interrupts but in reality that problem with non-atomic assignments asks for interrupt disable/enable, which will reduce the time available for interrupts anyway.