How can I find out whether or not micros(), delayMicroseconds() or the LCD library uses interrupts? (Arduino Uno platform) - atmega

Where do I look to find code that signifies that it uses interrupts? I've gone through wiring.c in the subfolder of Arduino, but it only leads to the function.
The issue is that when I enable CTC mode for Timer/Comp0, the LCD prints out complete jibberish, but when I disable CTC mode, it works perfectly fine.
Here is the timer initialization code:
void timerCompare0_ini(void){ // -Initialization of the Timer Compare 0
TCCR0A = 0; // This regulates the menu navigation arrow to show where user is pointing
TCCR0B = 0;
TCNT0 = 0;
OCR0B = 256;
// TCCR0A |= (1 << COM0B0) | (1 << COM0B1);
TCCR0A |= (1 << WGM01); // -CTC mode
TCCR0B |= ((1 << CS02) | (1 << CS00)); // -1024 prescaler
TIMSK0 |= (1 << OCIE0B); // -Enable timer compare interrupt
}

wiring.c is good place. delay() uses micros() which depends on running timer0 and overflow interrupt. delayMicroseconds() does internal pause based on instructions. BTW But both method has bug because when watchdog is set shorter than requested delay it reboots CPU. I.e. you need implement own functions.

Related

How to overwrite arduino library interruptHandler?

Good day!
I write code for an STM32f401xB/C board using the arduino IDE. I compile my code with stm32duino.
I am trying to write an EXTI interrupt handler but compiler flags me that I am trying to overwrite the handler function.
How should I go about with this problem?
Here is my code:
#define echo_pin PB9
void setup()
{
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
GPIOB->MODER &= ~(0x000C0000);
GPIOB->PUPDR &= ~(0x000C0000);
GPIOB->PUPDR |= 0x00080000;
pinMode(PC13, OUTPUT);
digitalWrite(PC13, LOW);
//enable clock and power on the syscfgen register
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN;
//there are 4 bits that have to be set to enable an interrupt
//there are 4 EXTICR register each 16 bits wide
//reset the bits in the register
SYSCFG->EXTICR[2] &= ~(0x00F0);
//set interrupt on pin PB9
SYSCFG->EXTICR[2] |= (0x0010);
//enables interupt on EXTI line
EXTI->IMR |= (1 << 9);
//set to trigger on both rising and falling edge, simulating the CHANGE
//flag in attachInterrupt() function
EXTI->RTSR |= (1 << 9);
EXTI->FTSR |= (1 << 9);
//enable the NVIC interrupt for EXTI9 to EXTI5 to lowest priority
NVIC_SetPriority(EXTI9_5_IRQn, 0x03);
NVIC_EnableIRQ(EXTI9_5_IRQn);
}
extern "C" { void EXTI9_5_IRQHandler(void){
//check the pending bit of the PB9 pin
if(EXTI->PR & (1 << 9)){
//reset the interrupt bit
EXTI->PR |= (1 << 9);
digitalWrite(PC13, HIGH);
}
}
}
void loop()
{
}
This is the error
home/admin1/.arduino15/packages/STMicroelectronics/tools/xpack-arm-none-eabi-gcc/10.3.1-2.3/bin/../lib/gcc/arm-none-eabi/10.3.1/../../../../arm-none-eabi/bin/ld: /tmp/arduino-sketch-E075A13F2405718203FB0E8501028A7D/libraries/SrcWrapper/stm32/interrupt.cpp.o: in function `EXTI9_5_IRQHandler':
interrupt.cpp:(.text.EXTI9_5_IRQHandler+0x0): multiple definition of `EXTI9_5_IRQHandler'; /tmp/arduino-sketch-E075A13F2405718203FB0E8501028A7D/sketch/Test Distance.ino.cpp.o:Test Distance.ino.cpp:(.text.EXTI9_5_IRQHandler+0x0): first defined here
collect2: error: ld returned 1 exit status
The issue you're running into is with your call to Extern "C". Calling Extern "C" prevents name mangling which is what the C++ compiler uses to differentiate between functions with the same name. What you need to do is use Extern "C" to provide a linkage to the original C function and then provide a separate definition. If you want to read a little more about Extern "C" here is a very brief intro. Depending on the version of the STM32F4 library you are using, you may also need to locate the "/stm32/{version}/libraries/SrcWrapper/src/stm32/interrupt.cpp" file and add __weak in front of the first definition of EXTI9_5_IRQHandler. This allows for a different definition of the function to be created but the original definition will remain as a fallback.
// Top of File
Extern "C" { void EXTI9_5_IRQHandler(void); }
// OTHER CODE
void EXTI9_5_IRQHandler(void){
//check the pending bit of the PB9 pin
if(EXTI->PR & (1 << 9)){
//reset the interrupt bit
EXTI->PR |= (1 << 9);
digitalWrite(PC13, HIGH);
}
}
This code cleans up the error but it is generally not common practice overwrite the default IRQHandlers. If you simply want to attach an interrupt service routine to the Arduino library for the STM32F4XX exposes a method called attachInterrupt. You can use it to assign a callback for an individual pin.
attachInterrupt({Pin#}, {callback_function}, RISING). Rising can be replaced with falling or both as the mode for when the interrupt is triggered.

Incremental 65535 steps to increase LED brightness to maximum over time (in hours), stay on at maximum (for hours) and ramp down (opposite of starup)

Trying to understand timing / dimming and interrupts using an Arduino Uno (or any other AVR) is being made very difficult by a serious lack of example code. Having found a sketch that starts from zero and ramps up the brightness, I have tried to adapt the code to prevent the continuous loop which occurs when the 16-bit register overflows.
The attached sketch starts up from zero light output and increases over a period of time - currently using the delay() function.
Attempting to adapt the code to prevent the loop from starting the entire process again and to allow the led to remain at the "top" brightness output for x (variable) number of hours has proved to be most elusive. As one of the contributors have noted this area of coding is one of the most difficult to master.
Any advice or guidance which will put me in the right direction will be most appreciated.
...
//fade over 65535 steps
// 16 bit PWM on any pin
// Example uses built in LED on pin 13 (PORTB bit 5)
// https://forum.arduino.cc/index.php?topic=348170.0
void setup() {
pinMode(13, OUTPUT);
cli(); // Disable all interrupts
TCCR1A = 0; // Clear all flags in control register A
TCCR1B = 0; // Clear all flags in control register B
TCNT1 = 0; // Zero timer 1 count
OCR1A = 32768; // Preload compare match register (50% duty cycle)
// No prescaler
//TCCR1B |= _BV(CS12);
//TCCR1B |= _BV(CS11);
TCCR1B |= _BV(CS10);
TIMSK1 |= _BV(OCIE1A); // Enable timer compare interrupt
TIMSK1 |= _BV(TOIE1); // Enable timer overflow interrupt
sei(); // enable all interrupts
}
void loop() {
for (unsigned int x = 1; x < 65535; x++) {
//cli();
OCR1A = x;
//sei();
delay(20);
}
}
ISR(TIMER1_OVF_vect) { // Timer1 overflow interrupt service routine
PORTB |= _BV(PORTB5); // Turn LED (pin 13) on
}
ISR(TIMER1_COMPA_vect) { // Timer1 compare interrupt service routine
PORTB &= ~_BV(PORTB5); // Turn LED off
}
...

How do I output a compare match to OC1B in Fast PWM mode on the ATtiny84?

My goal is to output a PWM signal from my ATtiny84 with 1ms high at 50hz. The clock is operating at 1mhz, so I've set the compare output mode such that the output pin should be cleared for 19000 clock ticks and be set for 1000.
The device is powered at 5V and I have an oscilloscope reading a flat 5V output from pin A5 (OC1B), no modulation. My code is here:
#include <avr\io.h>
void init_pwm_generator()
{
PORTA &= ~(1 << (PORTA5));
ICR1 = 20000;
TCCR1A = (1<<COM1B1) | (1<COM1B0) | (1<<WGM11);
TCCR1B = (1<<WGM13) | (1<<WGM12) | (1<<CS10);
}
int main(void)
{
DDRA |= (1 << (DDA5));
init_pwm_generator();
while(1)
{
OCR1B = ICR1 - 1000;
}
}
I can't figure out why this isn't working!
See the datasheet chapter 12.5 Input Capture Unit at page 91
The ICR1 Register can only be written when using a Waveform Generation mode that utilizesthe ICR1 Register for defining the counter’s TOP value. In these cases the Waveform Genera-tion mode (WGM13:0) bits must be set before the TOP value can be written to the ICR1Register.
So, correct initialization sequence will be as follows:
// Init the timer
TCCR1A = (1<<COM1B1) | (1<COM1B0) | (1<<WGM11);
TCCR1B = (1<<WGM13) | (1<<WGM12);
ICR1 = 19999; // set the top value
OCR1B = 19000; // set compare match value
TCCR1B |= (1<<CS10); // start the timer
Please note, for the timer period to be 20000 ticks you have to set TOP value to 19999 (since the timer counts from zero)

STM32F4 EXTI interrupts interfere with each other

I am working with STM32F407VGT6 MCU and I am having problem with external interrupts (EXTI). I have configured two pins as EXTI and they are PE7 and PE15. They are connected to HALL sensors driver and are detecting toot edges of trigger wheel. Ones is primary source with multiple tooth and other wheel is single tooth wheel which confirms position. The thing is they can work individually on their own without issues, but if I connect both of them, they start to interfere with each other and I am loosing position sync, because MCU is detecting false edges. I can recreate same behavior by connecting either pin to low signal and other to HALL driver. But if I disable EXTI and leave pin as a input the problem goes away. I have no idea what's going on here.
Also, I had issues with PE15 and EXTI before and it might be related to this. The EXTI was working only in EXTI_Trigger_Rising and EXTI_Trigger_Rising_Falling mode, but EXTI_Trigger_Falling was giving random edge detection, and only solution to this was to listen for both edges and debounce the one that I don't need. I couldn't find anything about this in datasheet.
This STM32F4 is giving me head aches and I running out of options. Well, the last option is to reroute the hall drivers to other pins and use input capture/timer.
Primary wheel config:
void Trigger_Configure_Primary(void) {
// GPIO
GPIOE->OSPEEDR |= (0x03 << (2 * 15)); // high speed
// EXTI
SYSCFG->EXTICR[3] = SYSCFG_EXTICR4_EXTI15_PE; // Tell system that you will use PE15 for EXTI15
EXTI->RTSR |= (1 << 15); // rising edge
EXTI->FTSR |= (1 << 15); // falling edge
EXTI->IMR |= (1 << 15); // Unmask EXTI15 interrupt
EXTI->PR |= (1 << 15); // Clear pending bit
/* Add IRQ vector to NVIC */
NVIC_SetPriority(EXTI15_10_IRQn, 0);
NVIC_EnableIRQ(EXTI15_10_IRQn);
}
Secondary wheel config:
void Trigger_Configure_Secondary(void) {
// GPIO
GPIOE->OSPEEDR |= (0x03 << (2 * 7)); // high speed
// EXTI
SYSCFG->EXTICR[1] = SYSCFG_EXTICR2_EXTI7_PE; // Tell system that you will use PE7 for EXTI7
EXTI->RTSR |= (1 << 7); // rising edge
EXTI->FTSR |= (1 << 7); // falling edge
EXTI->IMR |= (1 << 7); // Unmask EXTI7 interrupt
EXTI->PR |= (1 << 7); // Clear pending bit
/* Add IRQ vector to NVIC */
NVIC_SetPriority(EXTI9_5_IRQn, 0);
NVIC_EnableIRQ(EXTI9_5_IRQn);
}
IRQ handlers:
void EXTI9_5_IRQHandler(void) {
__disable_irq();
/* Make sure that interrupt flag is set */
if ((EXTI->PR & EXTI_Line7) != 0) {
// Secondary trigger IRQ
uint32_t now_nt = GET_TIMESTAMP();
uint8_t edge = ((GPIOE->IDR & SECONDARY_PIN) == 0 ? 0 : 1);
TD_Decode_Secondary_Trigger_Event(
now_nt,
edge
);
#ifdef DEBUG
// Stats
secondary_ticks = (GET_TIMESTAMP() - now_nt);
#endif
/* Clear interrupt flag */
EXTI->PR |= EXTI_Line7;
++s_cnt;
}
__enable_irq();
}
void EXTI15_10_IRQHandler(void) {
__disable_irq();
/* Make sure that interrupt flag is set */
if ((EXTI->PR & EXTI_Line15) != 0) {
// Primary trigger IRQ
uint32_t now_nt = GET_TIMESTAMP();
uint8_t edge = ((GPIOE->IDR & PRIMARY_PIN) == 0 ? 0 : 1);
if (primary_edge == edge) {
TD_Decode_Primary_Trigger(now_nt);
}
#ifdef DEBUG
// Stats
primary_ticks = (GET_TIMESTAMP() - now_nt);
#endif
/* Clear interrupt flag */
EXTI->PR |= EXTI_Line15;
++p_cnt;
}
__enable_irq();
}
RM0090, 12.3.6 Pending register (EXTI_PR):
This bit is cleared by programming it to ‘1’.
Thus, this code
/* Clear interrupt flag */
EXTI->PR |= EXTI_Line7;
Clears not only EXTI_Line7 but all pending interrupts because it reads EXTI-PR with 1 for all triggered interrupts, then OR bit EXTI_Line7 and writes all the 1-es back.
Use
/* Clear interrupt flag */
EXTI->PR = EXTI_Line7;

Arduino - Tone without delay

I'm trying to play a tone while changing something on an LCD display. I've searched around and tried protothreads, but it seems that the delay still blocks the program. I've also tried removing the delay altogether, but it skipped everything except the last note. Is there a way to play a tone without using delay? (millis perhaps?)
Sample tone sequence:
//Beats per Minute
#define BPM 250
//Constants, try not to touch, touch anyways.
#define Q 60000/BPM //Quarter note
#define W 4*Q //Whole note
#define H 2*Q //Half note
#define E Q/2 //Eigth note
#define S Q/4 //Sixteenth note
void toneFunction()
{
tone(tonePin,C5,Q);
delay(1+W);
tone(tonePin,C5,Q);
delay(1+W);
tone(tonePin,C5,Q);
delay(1+W);
tone(tonePin,C6,W);
}
You can set up a timer and put note changing logic into an interrupt service routine (ISR).
Each X milliseconds, the timer will reset and interrupt your main loop. The ISR will run and pick the next note and call the tone function. After exiting the ISR, the program continues from the point it was interrupted.
I have attached a code I used in one of my projects. The timer will interrupt the main loop every 50ms (20 Hz), therfore you will have to put your own numbers in OCR1A and the pre-scaler. Please read more about timer interrupt in arduino so that you will understand how to do it (for example here: http://www.instructables.com/id/Arduino-Timer-Interrupts/step2/Structuring-Timer-Interrupts/). You can also see the example at the end of this page (http://playground.arduino.cc/Code/Timer1) for a more user friendly way of doing this.
setup() {
....
/* Set timer1 interrupt to 20Hz */
cli();//stop interrupts
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
OCR1A = 781; // approximately 20Hz
TCCR1B |= (1 << WGM12);// turn on CTC mode
TCCR1B |= (1 << CS12) | (1 << CS10); // 1024 presxaler
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
sei();//allow interrupts
}
...
ISR(TIMER1_COMPA_vect){
// pick next note
}

Resources