for 4 days now, I am struggling to set up External interrupt on my STM32 and I have gone through tons of reading and other people's code to get it. But no luck.
I have two buttons and when pressing either one of them I expect to light up an LED, this example is only to get it working, I wanted to have something functional before proceeding and building rest of the code.
I am sorry if the code is a little messy, but I am working on neating my coding skills.
I've gone through manuals and datasheets but nothing seems to help.
Here is my main.c
#include "stm32l1xx_hal.h"
#include "buttons.h"
static void MX_GPIO_Init(void);
bool RightButtonFlag = 0;
bool LeftButtonFlag = 0;
int main(void)
{
HAL_Init();
SystemClock_Config();
controls_Interrupt_Init();
MX_GPIO_Init();
while (1)
{
if(RightButtonFlag){
Blue_ON();
}
if(LeftButtonFlag){
Green_ON();
}
}
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
{
Followed by part of stm32l1xx_it.c
#include "stm32l1xx_hal.h"
#include "stm32l1xx.h"
#include "stm32l1xx_it.h"
#include "buttons.h"
extern volatile uint8_t RightButtonFlag;
extern volatile uint8_t RightButtonFlag;
void EXTI15_10_IRQHandler(void)
{
if(GPIOC->IDR & GPIO_IDR_IDR_10){
RightButtonFlag = 1;
EXTI->PR |= EXTI_PR_PR10;
}
if(GPIOC->IDR & GPIO_IDR_IDR_11){
LeftButtonFlag = 1;
EXTI->PR |= EXTI_PR_PR11;
}
}
buttons.c
void controls_Interrupt_Init(void){
RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; /* Enable System Configuration Register */
SYSCFG->EXTICR[3] |= SYSCFG_EXTICR3_EXTI11_PC; /* Set up External Interrupt for Pin 11 Port C */
SYSCFG->EXTICR[3] |= SYSCFG_EXTICR3_EXTI10_PC; /* Set up External Interrupt for Pin 10 Port C */
EXTI->IMR |= EXTI_IMR_MR11;
EXTI->IMR |= EXTI_IMR_MR10;
EXTI->FTSR |= EXTI_FTSR_TR11; /* Falling trigger Selection Reg. Trigger 11 */
EXTI->FTSR |= EXTI_FTSR_TR10; /* Falling trigger Selection Reg. Trigger 10 */
NVIC_SetPriority(EXTI15_10_IRQn,1); /* Set Interrupt priority for pins 10-15 */
NVIC_EnableIRQ(EXTI15_10_IRQn); /* Enable NVIC for Pins Between 10-15 */
}
and buttons.h
void controls_Interrupt_Init(void);
#define Blue_ON() (HAL_GPIO_WritePin(BLUE_LED_PORT, BLUE_LED_PIN, 1))
#define Green_ON() (HAL_GPIO_WritePin(GREEN_LED_PORT, GREEN_LED_PIN, 1))
I am fairly new to coding and with my poor experience I expect to have screwed up something very simple.
You have to declare the flags as volatile. That's a hint to the compiler that the variable can change any time, independent of the normal program flow.
volatile bool RightButtonFlag = 0;
volatile bool LeftButtonFlag = 0;
When there is no volatile there, the compiler can assume that the flags never change in the main loop, and optimize it that way, that the variables will be loaded only once, before the loop.
Declaring them volatile only in the scope of the interrupt handler does no good, because the optimization will still take place in main(), where the volatile declaration is not visible.
It is good practice to move the declaration to a header file, and include that header everywhere the variable is referenced. Then the compiler can check that the types are indeed compatible.
UPDATE
The interrupt handler makes little sense. You set EXTI to detect a falling edge, then check if the input is high. Checking the GPIO data register is not reliable anyway, due to the bouncing effect of mechanical buttons.
You should rather check EXTI->PR in the handler, and reset the pending bit with a simple assignment instead of |=, otherwise you could accidentally clear another pending bit too.
void EXTI15_10_IRQHandler(void)
{
if(EXTI->PR & EXTI_PR_PR10){
RightButtonFlag = 1;
EXTI->PR = EXTI_PR_PR10;
}
if(EXTI->PR & EXTI_PR_11){
LeftButtonFlag = 1;
EXTI->PR = EXTI_PR_PR11;
}
}
You can still check somewhere if GPIOC->IDR actually reflects the button state, to eliminate possible hardware problems.
You can also try setting EXTI->SWIER from the debugger, or in the code, to simulate a button press.
Related
I am new to Free RTOS, and I was following some tutorial line by line but things didn't sum up correctly, I used free RTOS to toggle 3 LEDS but it lights just 2 of them without toggling! random 2 LEDs, whatever I change the priorities or the delay time of toggling. random 2 LEDs just switch on and nothing more, I tried the code on proteus simulation and on real hardware and the same problem exists. can someone help me with this?
M/C: ATMEGA32A
RTOS: FreeRTOS
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
/* FreeRTOS files. */
#include "FreeRTOS.h"
#include "task.h"
#include "croutine.h"
#include "FreeRTOSConfig.h"
/* Define all the tasks */
static void ledBlinkingtask1(void* pvParameters);
static void ledBlinkingtask2(void* pvParameters);
static void ledBlinkingtask3(void* pvParameters);
int main(void) {
/* Call FreeRTOS APIs to create tasks, all tasks has the same priority "1" with the
same stack size*/
xTaskCreate( ledBlinkingtask1,"LED1",
configMINIMAL_STACK_SIZE, NULL, 1, NULL );
xTaskCreate( ledBlinkingtask2,"LED2",
configMINIMAL_STACK_SIZE, NULL,1, NULL );
xTaskCreate( ledBlinkingtask3,"LED3",
configMINIMAL_STACK_SIZE, NULL,1, NULL );
// Start the RTOS kernel
vTaskStartScheduler();
/* Do nothing here and just run infinte loop */
while(1){};
return 0;
}
static void ledBlinkingtask1(void* pvParameters){
/* Define all variables related to ledBlinkingtask1*/
const uint8_t blinkDelay = 100 ;
/* make PB0 work as output*/
DDRB |= (1<<0); //PB0
/* Start the infinte task 1 loop */
while (1)
{
PORTB ^= (1<<0); //toggle PB0 //PB0
vTaskDelay(blinkDelay); //wait some time
}
}
static void ledBlinkingtask2(void* pvParameters){
/* Define all variables related to ledBlinkingtask2*/
const uint8_t blinkDelay = 100;
/* make PB1 work as output*/
DDRB |= (1<<1);//PB0
/* Start the infinte task 2 loop */
while (1)
{
PORTB ^= (1<<1); //toggle PB0 //PB0
vTaskDelay(blinkDelay); //wait some time
}
}
static void ledBlinkingtask3(void* pvParameters){
/* Define all variables related to ledBlinkingtask3*/
const uint16_t blinkDelay = 100;
/* make PB2 work as output*/
DDRB |= (1<<2); //PB2
/* Start the infinte task 3 loop */
while (1)
{
PORTB ^= (1<<2); //toggle PB0 //PB0
vTaskDelay(blinkDelay); //wait some time
}
}
ps: every task works well alone but not together!
As already mentioned in comments - the major problem seems to be that access to the port register driving the LEDs is neither
PORTB ^= (1<<0); // in task 1
[...]
PORTB ^= (1<<1); // in task 2
[...]
PORTB ^= (1<<2); // in task 3
atomic
protected (by disabling interrupts during access, or by RTOS measures such as a mutex)
deployed to one unique task:
It may be misleading that the access to HW register is performed using a single instruction in the C code every time.
Still, this doesn't help because the compiler generates several assembler instructions (e.g., load previous port value to register, modify that register value, write it back to the port). This way, one task can interrupt another between those assembler/CPU instructions and modify the intermediate value.
Several tasks writing back "their" register value to the port in turn can revert what other task(s) may have just written to the port, so you miss a blinky event (or several, if this happens systematically).
The solution is therefore to protect the assignments against each other.
In the same order as numbered above, this may mean either of the following:
Check if the hardware offers a "set value" or "reset value" register beside the main PORTB port register. If so, writing a single bit to that port would be an atomic way to have the LED toggle.
I'm sorry that I don't know the hardware interface of Atmega. Maybe, this isn't possible, and you have to go on directly to 2. and 3.
a. Disable interrupts before changing the port register, reenable it afterwards. This way, the task scheduler won't run during that period (= critical section) and nobody disturbs the task that accesses the hardware.
b. Use taskENTER_CRITICAL()/taskEXIT_CRITICAL()
c. Use a mutex or similar.
Create a fourth task which waits (blocking) at a mailbox/queue.
Whenever it receives a value from the mailbox, it processes it (e.g., by XOR-ing it to the port register).
The three existing tasks don't access the LED port register themselves, but instead send such a value (= request message) to the new task.
Assign a higher priority to the new task in order to get a smooth blinking pattern.
If option 1. is possible on your controller, it is fastest (but it requires certain features in the hardware platform...). Otherwise, I agree with the hint from #Richard, option 2.b. are fastest (2.a. is as fast, but not as clean because you break the layering of the FreeRTOS lib).
Option 2.c. may introduce a notable overhead, and option 3. is very clean but a complete overkill in your situation: If your question is really only about blinking LEDs, please leave the bulldozer inside the garage and choose option 2.
Every time I enable the timer it instantly activates the Interrupt. No matter how I try to prescale it. only ARR seems to work but 16 bit with 0,5MHz clock gives me ~160ms maneuver.
#define SYSCLK_FREQ 524288
void timer_init(uint16_t detonation_delay_ms);
int main(void){
RCC->APB2ENR = RCC_APB2ENR_TIM22EN;
TIM22->PSC = (SYSCLK_FREQ/1000)-1;
NVIC_EnableIRQ(TIM22_IRQn);
NVIC_SetPriority(TIM22_IRQn,4);
}
/* calling function */
timer_init(65535);
/* calling function */
void timer_init(uint16_t detonation_delay_ms){
TIM22->CR1 &= ~TIM_CR1_CEN;
TIM22->SR=0;
TIM22->ARR = detonation_delay_ms;
TIM22->CR1 |= TIM_CR1_CEN;
TIM22->SR = 0;
}
void TIM22_IRQHandler(void){
TIM22->CR1 &= ~TIM_CR1_CEN;
TIM22->SR=0;
GPIOB->BSRR = GPIO_BSRR_BS_7;
}
I wish that calling function makes the timer tick till the called value in milisec. But no matter how I set it up it ends up with no scaled timer and instant interrupt after calling it.
Correct way to do it?
TIM22->DIER = TIM_DIER_UIE;
TIM22->ARR = 65535-detonation_delay_ms;
TIM22->EGR = TIM_EGR_UG;
TIM22->CR1 |= TIM_CR1_OPM | TIM_CR1_CEN;
TIM22->SR=0;
Do not delay in interrupts
you enable the timer then set the ARR which is wrong - first set ARR and prescaller, then generate the UG event using the EGR register, then enable the timer.
Works like a charm. Just because I got help here will describe for future interested people.
The way to get the interrupt working for the timers is to generate interrupt 'by hand' once. It's okay to do it because you can control what's happening during the interrupt by a single 'if'.
/* TIMER Enable */
RCC->APB2ENR = RCC_APB2ENR_TIM22EN;
I had a problem with the above declaration, dunno why but it wasn't working after declaring some more modules before it. Had to put it on higher on the list. Manual does not say why it happened.
/* Configure TIM22 interrupt */
TIM22->PSC = (SYSCLK_FREQ/1000)-1; /* Prescaler TIMERA 22 */
TIM22->DIER = TIM_DIER_UIE;
TIM22->CNT = 0;
TIM22->EGR = TIM_EGR_UG;
NVIC_EnableIRQ(TIM22_IRQn); /* Zalaczenie przerwania od TIMER'a */
NVIC_SetPriority(TIM22_IRQn,4); /* Ustawienie priorytetu przerwania od TIMER'a */
The prescaler meant to be 1ms so I divided 524288 of my core speed. Then enabling the interrupt, resetting the counter to make sure it starts from 0 and then manually generating the interrupt. And it does the interrupt 'loop' once but with a single 'if' and variable, I can control what it does.
So what I do, I am calling a function that set the clock and enables the count inside another function enable = 1; timer_init(ms);
Then comes the function call
void timer_init(uint16_t ms)
{
TIM22->CNT = 65535-ms;
TIM22->CR1 |= TIM_CR1_CEN;
}
void TIM22_IRQHandler(void)
/* Up-Counter milisec */
{
if(TIM22->CR1 & TIM_CR1_CEN) {TIM22->CR1 &= ~TIM_CR1_CEN;}
if(TIM22->SR & TIM_SR_UIF) {
if(enable == 1){
GPIOB->BSRR = GPIO_BSRR_BS_7;
}
}
TIM22->SR=0;
}
And the interrupt.
Thanks a lot!Have fun with registers!
I am new here and hoping to help and be helped.
My question is about systick interrupts on a tm4c123gh6pm m4 processor. When I use systick as timer (disable interrupt) it works properly, but when I enable interrupt, as the systick counter reaches the value 0, which should trigger the interrupt, it goes to IntDefaultHandler(void) which is in the startup.c file. I don't even enable global interrupt. But when I enable the global interrupt I am getting same result. I am sharing the code below, and please pay attention to the commented lines. By the way, I am using iar as my compiler.
#include <stdint.h>
#include <stdio.h>
#include "inc/tm4c123gh6pm.h"
volatile unsigned long Counts=0;
void SysTick_Init(unsigned long period){ // priority 2
NVIC_ST_CTRL_R = 0; // disable SysTick during setup
NVIC_ST_RELOAD_R = period-1;// reload value
NVIC_ST_CURRENT_R = 0; // any write to current clears it
NVIC_SYS_PRI3_R = (NVIC_SYS_PRI3_R&0x00FFFFFF)|0x40000000;
NVIC_ST_CTRL_R = 0x05; // Main problem is here, 0x05 means disable interrupt
// 0x07 means enable interrup. but 0x07 doesnt work for me
}
void SysTick_Handler(void){
GPIO_PORTF_DATA_R ^= 0x04; // toggle PF2
Counts = Counts + 1;
printf("interrupt working\n");
}
//*****************************************************************************
//
// Blink the on-board LED.
//
//*****************************************************************************
int
main(void)
{
volatile uint32_t ui32Loop;
unsigned long now;
//
// Enable the GPIO port that is used for the on-board LED.
//
SYSCTL_RCGC2_R = SYSCTL_RCGC2_GPIOF;
//
// Do a dummy read to insert a few cycles after enabling the peripheral.
//
ui32Loop = SYSCTL_RCGC2_R;
//
// Enable the GPIO pin for the LED (PF2). Set the direction as output, and
// enable the GPIO pin for digital function.
//
GPIO_PORTF_DIR_R = 0x04;
GPIO_PORTF_DEN_R = 0x04;
SysTick_Init(16000); // initialize SysTick timer, every 1ms
//
// Loop forever.
//
while(1)
{ now = NVIC_ST_CURRENT_R; // get systick current value
printf("%u\n",now);
if((NVIC_ST_CTRL_R&0x00010000)!=0){ // check Systick flag
GPIO_PORTF_DATA_R ^= 0x04;
printf("timer working\n");
}
}
}
Edit: I have tried a working exapmle wrote by valvano, and this time it goes HardFault_Handler instead of SysTick_Handler. Code is so simple I don't understand the problem. Code is below.
// PeriodicSysTickInts.c
// Runs on LM4F120 or TM4C123
// Use the SysTick timer to request interrupts at a particular period.
// Daniel Valvano
// September 14, 2013
/* This example accompanies the book
"Embedded Systems: Introduction to ARM Cortex M Microcontrollers"
ISBN: 978-1469998749, Jonathan Valvano, copyright (c) 2013
Volume 1, Program 9.6
"Embedded Systems: Real Time Interfacing to ARM Cortex M Microcontrollers",
ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2013
Volume 2, Program 5.12, section 5.7
Copyright 2013 by Jonathan W. Valvano, valvano#mail.utexas.edu
You may use, edit, run or distribute this file
as long as the above copyright notice remains
THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
For more information about my classes, my research, and my books, see
http://users.ece.utexas.edu/~valvano/
*/
// oscilloscope or LED connected to PF2 for period measurement
#define GPIO_PORTF_DATA_R (*((volatile unsigned long *)0x400253FC))
#define GPIO_PORTF_DIR_R (*((volatile unsigned long *)0x40025400))
#define GPIO_PORTF_AFSEL_R (*((volatile unsigned long *)0x40025420))
#define GPIO_PORTF_DEN_R (*((volatile unsigned long *)0x4002551C))
#define GPIO_PORTF_AMSEL_R (*((volatile unsigned long *)0x40025528))
#define GPIO_PORTF_PCTL_R (*((volatile unsigned long *)0x4002552C))
#define SYSCTL_RCGC2_R (*((volatile unsigned long *)0x400FE108))
#define NVIC_SYS_PRI3_R (*((volatile unsigned long *)0xE000ED20)) // Sys. Handlers 12 to 15 Priority
#define NVIC_ST_CTRL_R (*((volatile unsigned long *)0xE000E010))
#define NVIC_ST_RELOAD_R (*((volatile unsigned long *)0xE000E014))
#define NVIC_ST_CURRENT_R (*((volatile unsigned long *)0xE000E018))
void DisableInterrupts(void); // Disable interrupts
void EnableInterrupts(void); // Enable interrupts
long StartCritical (void); // previous I bit, disable interrupts
void EndCritical(long sr); // restore I bit to previous value
void WaitForInterrupt(void); // low power mode
volatile unsigned long Counts = 0;
// **************SysTick_Init*********************
// Initialize SysTick periodic interrupts
// Input: interrupt period
// Units of period are 62.5ns (assuming 16 MHz clock)
// Maximum is 2^24-1
// Minimum is determined by length of ISR
// Output: none
void SysTick_Init(unsigned long period){
NVIC_ST_CTRL_R = 0; // disable SysTick during setup
NVIC_ST_RELOAD_R = period-1;// reload value
NVIC_ST_CURRENT_R = 0; // any write to current clears it
NVIC_SYS_PRI3_R = (NVIC_SYS_PRI3_R&0x00FFFFFF)|0x40000000; // priority 2
// enable SysTick with core clock and interrupts
NVIC_ST_CTRL_R = 0x07;
EnableInterrupts();
}
// Interrupt service routine
// Executed every 62.5ns*(period)
void SysTick_Handler(void){
GPIO_PORTF_DATA_R ^= 0x04; // toggle PF2
Counts = Counts + 1;
}
int main(void){
SYSCTL_RCGC2_R |= 0x00000020; // activate port F
Counts = 0;
GPIO_PORTF_DIR_R |= 0x04; // make PF2 output (PF2 built-in LED)
GPIO_PORTF_AFSEL_R &= ~0x04;// disable alt funct on PF2
GPIO_PORTF_DEN_R |= 0x04; // enable digital I/O on PF2
// configure PF2 as GPIO
GPIO_PORTF_PCTL_R = (GPIO_PORTF_PCTL_R&0xFFFFF0FF)+0x00000000;
GPIO_PORTF_AMSEL_R = 0; // disable analog functionality on PF
SysTick_Init(16000); // initialize SysTick timer
EnableInterrupts();
while(1){ // interrupts every 1ms, 500 Hz flash
WaitForInterrupt();
}
}
and all project files SysTickInt
For your first comment, that the interrupt default handler gets called, this is due to the fact that you did not declare an interrupt handler for the systick interrupt within the startup file. You can do it for example in the following way in the startup file.
extern void systick_isr(void); // somewhere you have to define this interrupt handler
Furthermore you have to add the function name of your interrupt handler to the vector table (excerpt below) in the startup file. Every line represents a certain interrupt handler, take a look at the comments, they tell you which one you have to adapt. For example you can see that the GPIOA interrupt handler will call the default interrupt handler at the moment. The same happens for you, at least for the first part of your question.
//*****************************************************************************
//
// The vector table. Note that the proper constructs must be placed on this to
// ensure that it ends up at physical address 0x0000.0000 or at the start of
// the program if located at a start address other than 0.
//
//*****************************************************************************
#pragma DATA_SECTION(g_pfnVectors, ".intvecs")
void (* const g_pfnVectors[])(void) =
{
(void (*)(void))((uint32_t)&__STACK_TOP),
// The initial stack pointer
ResetISR, // The reset handler
NmiSR, // The NMI handler
FaultISR, // The hard fault handler
IntDefaultHandler, // The MPU fault handler
IntDefaultHandler, // The bus fault handler
IntDefaultHandler, // The usage fault handler
0, // Reserved
0, // Reserved
0, // Reserved
0, // Reserved
IntDefaultHandler, // SVCall handler
IntDefaultHandler, // Debug monitor handler
0, // Reserved
IntDefaultHandler, // The PendSV handler
systick_isr, // The SysTick handler
IntDefaultHandler, // GPIO Port A
IntDefaultHandler, // GPIO Port B
IntDefaultHandler, // GPIO Port C
IntDefaultHandler, // GPIO Port D
...
Regarding the comment in your own code, how the interrupt can be enabled or disabled please be aware that this does not seem to be right. Enabling or disabling the systick interrupt can be achieved by setting the bit number one of the STCTRL register accordingly. The picture below shows the register. To enable the interrupt you have to set the bit number one high (NVIC_ST_CTRL_R |= 0x02;) to disable the interrupt you have to clear the bit (NVIC_ST_CTRL_R &= ~0x02;)
I am currently using an interrupt to reset an ATTiny20. Here is the relevant code:
int main(void)
{
...
// Set up interrupt for reset button (PCINT5)
SREG |= 1<<7; // Enable global interrupts
GIMSK |= 1<<PCIE0; // Enable Pin Change Interrupt 0 (enables interrupts on PCINT[7:0]
PCMSK0 |= 1<<PCINT5; // Enable PCINT5 (physical pin 8) interrupt
...
}
The interrupt-handling function:
ISR(PCINT0_vect)
{
if (!(BUTTON_1_PORT & 1<<BUTTON_1_PIN)) // Only reset if button is pushed
{
wdt_enable(WDTO_2S);
while(1){};
}
}
This works quite well - when the button is pushed the system freezes for 2 seconds and then resets... and promptly gets stuck in a reset loop. A bit of googling uncovered the culprit: on newer chips the watchdog timer is left enabled (at its shortest delay setting) after a watchdog reset. The following code is meant to remedy this issue:
// Disable watchdog on reset
void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3")));
void wdt_init(void)
{
// MCUSR = 0; // See below for reason for commenting this line
wdt_disable();
return;
}
*N.B. MCUSR = 0 is commented out because MCUSR does not exist on the ATTiny20. I have tried replacing it with SREG = 0 but to no avail.
Even with this code in place, which should disable the watchdog timer, the issue persists. Flashing LEDs on the device indicate that the program is running through part of the main() function before it resets, but putting wdt_disable(); at the top of main() has not helped either.
Is there something critical that I'm missing re: the ATTiny20? Something I've missed in the datasheet? The problem - and solution - seem so obvious, but I'm stumped. I'm using Atmel Studio 6.1.
// Disable watchdog on reset
void wdt_init(void) __attribute__((naked)) __attribute__((section(".init3")));
void wdt_init(void)
{
// This is the flag that must be cleared on an ATTiny20 before the WDT can be disabled
/***************/
/* RSTFLR = 0; */
/***************?
wdt_disable();
return;
}
I am programming a AVR MCU.
It has a POT that reads off an analogue pin. It seems that the interrupt is constantly called, and it must be called during a LCD_display method as it is messing with my LCD.
Is there a way to STOP the inturrupts until after the block is run?
int main(void)
{
/*Turn on ADC Interrupt */
ADCSRA |= (1 << ADIE);
/*Turn On GLobal Interrupts*/
sei();
/* Intalise LCD */
lcd_init(LCD_DISP_ON); /* initialize display, cursor off */
lcd_clrscr();
lcd_puts("READY");
DDRB &= ~(1 << PINB5); //set input direction
ADC_Init(128, 0); //initalize ADC
while (1)
{
if (!bit_is_clear(PINB, 5))
{
_delay_ms(500);
if (!pressed)
{
lcd_gotoxy(0,0);
lcd_clrscr();
lcd_puts("test"); //Doesnt work unless I dont comment out the last line of interrupt
pressed = 1;
}
}
/* INTERRUPTS */
//ADC INTERRUPT
ISR(ADC_vect)
{
char adcResult[4];
uint8_t theLowADC = ADCL;
uint16_t theTenBitResults = ADCH<<8 | theLowADC;
itoa(theTenBitResults, adcResult, 10);
ADCSRA |= (1 << ADSC); //next conversion *if i comment out this line it works*
}
If the interrupt handler behaves bad with your code, the reason could be you spend too much time in the interrupt handler. You should only do critical work in the interrupt handler and defer the less critical work in the application code; use a volatile flag shared between the handler and the application code to let the application code know if it has work to do. In your example, you should defer the itoa call in the application code.
Use cli(); to disable interrupts and sei(); to enable them again after you finished the display routine.
Which MCU are you using? You should propably use a timer instead of a delay of 500ms.
I believe, I am little late but still I had the same issue I solved it using the following method,
Interrupts are enabled using two flags
1.A global interrupt flag
2.A module related interrupt flag (in your case ADC)
You can have control over module related flag, in your case in the ADCSRA control register there is a flag named ADIE- ADC Interrupt Enable flag you can use that to control the Interrupts.
For example,
In main function you can enable the flag and in ISR disable the flag.
main()
{
//enable global flag and ADC flag
while(1)
{
//your logic
// enable ADC flag
}
}
ISR()
{
//disable the ADC flag
}
I hope this solves the issue you are having.