I'm currently working on a SAME70 board made by Atmel. I plugged on it an extention OLED1 board (Atmel too) on EXT1 port. My goal is to recover the information about interrupt type (falling or raising) when I'm pressing the button 3 on OLED1 board. I have a function which allows me to set the different registers related to an interrupts. But unfortunately the register which indicates the polarity (FLHSR) stay always at 0 whatever the state of the button.
Below my code.
#include <asf.h>
void set_Interupt_Pin()
{
uint32_t mask = 1 << 19; /*bitmasking*/
PIOA->PIO_IER = mask; /*enable interruptions*/
PIOA->PIO_AIMER = mask; /*add new interruption*/
PIOA->PIO_ESR = mask; /*set interrupt source on edge*/
PIOA->PIO_REHLSR = mask; /* set interrupt to rising edge*/
PIOA->PIO_FELLSR= mask; /* set interrupt to falling edge*/
NVIC_DisableIRQ(ID_PIOA);
NVIC_ClearPendingIRQ(ID_PIOA);
NVIC_EnableIRQ(ID_PIOA); /*set NVIC to get interruptions from PIOA*/
NVIC_SetPriority(ID_PIOA, 4); /*priority 4*/
}
void PIOA_Handler(void)
{
printf("FRLHSR: %x\n",PIOA->PIO_FRLHSR); /*state of polarity event */
printf("ISR: %x\n",PIOA->PIO_ISR);
printf("ELSR: %x\n",PIOA->PIO_ELSR);
printf("AIMMR: %x\n",PIOA->PIO_AIMMR);
}
int main(void)
{
const usart_serial_options_t usart_serial_options = {
.baudrate = CONF_UART_BAUDRATE,
.charlength = CONF_UART_CHAR_LENGTH,
.paritytype = CONF_UART_PARITY,
.stopbits = CONF_UART_STOP_BITS
};
sysclk_init();
board_init();
stdio_serial_init(CONF_UART, &usart_serial_options);
set_Interupt_Pin();
while(1){}
}
You can see here the result of print when I press button (first part) and I release button (second part).
Best regards
Related
I wrote code for generation square pulse. Everything works fine till I activate ADC Interrupt by NVIC commands. Is ADC IRQ Handler wrote correctly?(I am specious on Handler). ADC Sets on continuous mode by only one channel is using. End_of_Conversion and End_of_Sequence Interrupt flag have been set.
#include <stdint.h>
#include "stm32f0xx.h"
//static __IO uint32_t RPM;
//uint32_t RPM=1000;
#define DUTY_CYCLE 0.1
void SysTick_Handler(void);
void ADC1_IRQHandler(void);
void Delay_10us(__IO uint32_t nTime);
static __IO uint32_t TimingDelay;
static __IO uint32_t adcValue;
//int calibration_factor;
uint32_t rpm;
int global_counter=0;
int main(void)
{
// Set SysTick for create 10 microsecond delay
if(SysTick_Config(80))
{
while(1);
}
//CLOCK
RCC->CR|=RCC_CR_HSEON;
while(!(RCC->CR&RCC_CR_HSERDY));
RCC->CR|=RCC_CR2_HSI14ON;
while(!(RCC->CR2|=RCC_CR2_HSI14RDY));
RCC->CFGR|=RCC_CFGR_SW_HSE;
while(!(RCC->CFGR&=RCC_CFGR_SWS_HSE));
RCC->APB2ENR|=RCC_APB2ENR_ADCEN;
// ADC1->CFGR2|=ADC_CFGR2_CKMODE_1;
RCC->AHBENR|=RCC_AHBENR_GPIOAEN;
//GPIO
GPIOA->MODER|=GPIO_MODER_MODER4_0;
GPIOA->PUPDR|=GPIO_PUPDR_PUPDR4_0;
GPIOA->ODR|=GPIO_ODR_4;
GPIOA->MODER|=GPIO_MODER_MODER5;
//NVIC
NVIC_EnableIRQ(ADC1_COMP_IRQn);/*if I comment this two lines everything works*/
NVIC_SetPriority(ADC1_COMP_IRQn,0);/*if I comment this two lines everything works*/
//ADC
ADC1->CR&=~ADC_CR_ADEN;
ADC1->SMPR|=ADC_SMPR1_SMPR;
ADC1->CFGR1|=ADC_CFGR1_CONT;
ADC1->IER|=ADC_IER_EOSIE|ADC_IER_EOCIE;
ADC1->CHSELR|=ADC_CHSELR_CHSEL5;
// for(int i=0;i<10;i++);
// ADC1->CR|=ADC_CR_ADCAL;
// while(ADC1->CR&ADC_CR_ADCAL);
// calibration_factor=ADC1->DR;
for(int i=0;i<10;i++);
ADC1->ISR|=ADC_ISR_ADRDY;
ADC1->CR|=ADC_CR_ADEN;
while(!(ADC1->ISR&=ADC_ISR_ADRDY));
ADC1->CR|=ADC_CR_ADSTART;
/* Loop forever */
int counter=0;
while(1){
if(rpm<250){rpm=250;}
int T=10000/rpm;
int OnDelay=T*DUTY_CYCLE;
int OffDelay=T*(1-DUTY_CYCLE);
GPIOA->ODR &=~GPIO_ODR_4;
Delay_10us(OffDelay);
GPIOA->ODR|=GPIO_ODR_4;
Delay_10us(OnDelay);
counter++;
if(counter==59)
{
GPIOA->ODR &=~GPIO_ODR_4;
Delay_10us(2*T);
counter=0;
continue;
}
}
}
void Delay_10us(__IO uint32_t nTime)
{
TimingDelay = nTime;
while(TimingDelay != 0);
}
void SysTick_Handler(void){
if (TimingDelay != 0x00)
{
TimingDelay--;
}
}
void ADC1_IRQHandler()
{
//
}
Your program enters ADC1_IRQHandler and stays there forever, since the handler is empty.
If you've enabled an interrupt, you must handle it - at least clear the interrupt source. And don't look at the SysTick_Handler it is a special case with autoreset. For other interrupts the corresponding status bit must be reset, or a special sequence of operations performed. Details are usually found in the description of a status register, in your case it is ADC_ISR.
With End_Of_Conversion and End_Of_Sequence enabled, the interrupt could be triggered by the EOC and EOSEQ status bits. Both could be cleared by writing 1 to it. The handler should look something like this:
void ADC1_IRQHandler()
{
if(ADC1->ISR & ADC_ISR_EOC)
{
//Handle end of conversion
ADC1->ISR = ADC_ISR_EOC;
}
if(ADC1->ISR & ADC_ISR_EOSEQ)
{
//Handle end of sequence
ADC1->ISR = ADC_ISR_EOSEQ;
}
}
The name of a handler depends on the startup used, it must match name of a placeholder in the interrupt vector table of the startup file. In Cube-generated projects this is an assembler file (.s) in Startup folder (eg. /Core/Startup/startup_stm32f407zgtx.s)
I am new to programming. I am working on an esp8266 using it's RTOS SDK. I am trying to make sense of one of it's example code on GPIO use and GPIO interrupts. So from what I have understood the program uses a struct variable to store the various configuration settings of a particular pin or pins. But the source of my confusion is that a single struct variable has been defined for configuring all the pins and the components of input and output pins have been assigned values on the same variable name. Wouldn't the downstream struct component override the previous struct component? The code works fine and still works fine when I defined two different struct variables for input and output.
Please have a look at the code.
gpio_config_t io_conf;
//disable interrupt
io_conf.intr_type = GPIO_INTR_DISABLE;
//set as output mode
io_conf.mode = GPIO_MODE_OUTPUT;
//bit mask of the pins that you want to set,e.g.GPIO15/16
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
//disable pull-down mode
io_conf.pull_down_en = 0;
//disable pull-up mode
io_conf.pull_up_en = 0;
//configure GPIO with the given settings
gpio_config(&io_conf);
//interrupt of rising edge
io_conf.intr_type = GPIO_INTR_POSEDGE;
//bit mask of the pins, use GPIO4/5 here
io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
//set as input mode
io_conf.mode = GPIO_MODE_INPUT;
//enable pull-up mode
io_conf.pull_up_en = 1;
gpio_config(&io_conf);
So my confusion is that shouldn't the io_conf.intr_type = GPIO_INTR_DISABLE be overridden by io_conf.intr_type = GPIO_INTR_POSEDGE and so on?
Here is the complete code. If anybody could help or share some useful link I would be very grateful.
/* gpio example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/gpio.h"
#include "esp_log.h"
#include "esp_system.h"
static const char *TAG = "main";
/**
* Brief:
* This test code shows how to configure gpio and how to use gpio interrupt.
*
* GPIO status:
* GPIO15: output
* GPIO16: output
* GPIO4: input, pulled up, interrupt from rising edge and falling edge
* GPIO5: input, pulled up, interrupt from rising edge.
*
* Test:
* Connect GPIO15 with GPIO4
* Connect GPIO16 with GPIO5
* Generate pulses on GPIO15/16, that triggers interrupt on GPIO4/5
*
*/
#define GPIO_OUTPUT_IO_0 15
#define GPIO_OUTPUT_IO_1 16
#define GPIO_OUTPUT_PIN_SEL ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1))
#define GPIO_INPUT_IO_0 4
#define GPIO_INPUT_IO_1 5
#define GPIO_INPUT_PIN_SEL ((1ULL<<GPIO_INPUT_IO_0) | (1ULL<<GPIO_INPUT_IO_1))
static xQueueHandle gpio_evt_queue = NULL;
static void gpio_isr_handler(void *arg)
{
uint32_t gpio_num = (uint32_t) arg;
xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}
static void gpio_task_example(void *arg)
{
uint32_t io_num;
for (;;) {
if (xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
ESP_LOGI(TAG, "GPIO[%d] intr, val: %d\n", io_num, gpio_get_level(io_num));
}
}
}
void app_main(void)
{
gpio_config_t io_conf;
//disable interrupt
io_conf.intr_type = GPIO_INTR_DISABLE;
//set as output mode
io_conf.mode = GPIO_MODE_OUTPUT;
//bit mask of the pins that you want to set,e.g.GPIO15/16
io_conf.pin_bit_mask = GPIO_OUTPUT_PIN_SEL;
//disable pull-down mode
io_conf.pull_down_en = 0;
//disable pull-up mode
io_conf.pull_up_en = 0;
//configure GPIO with the given settings
gpio_config(&io_conf);
//interrupt of rising edge
io_conf.intr_type = GPIO_INTR_POSEDGE;
//bit mask of the pins, use GPIO4/5 here
io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
//set as input mode
io_conf.mode = GPIO_MODE_INPUT;
//enable pull-up mode
io_conf.pull_up_en = 1;
gpio_config(&io_conf);
//change gpio intrrupt type for one pin
gpio_set_intr_type(GPIO_INPUT_IO_0, GPIO_INTR_ANYEDGE);
//create a queue to handle gpio event from isr
gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
//start gpio task
xTaskCreate(gpio_task_example, "gpio_task_example", 2048, NULL, 10, NULL);
//install gpio isr service
gpio_install_isr_service(0);
//hook isr handler for specific gpio pin
gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void *) GPIO_INPUT_IO_0);
//hook isr handler for specific gpio pin
gpio_isr_handler_add(GPIO_INPUT_IO_1, gpio_isr_handler, (void *) GPIO_INPUT_IO_1);
//remove isr handler for gpio number.
gpio_isr_handler_remove(GPIO_INPUT_IO_0);
//hook isr handler for specific gpio pin again
gpio_isr_handler_add(GPIO_INPUT_IO_0, gpio_isr_handler, (void *) GPIO_INPUT_IO_0);
int cnt = 0;
while (1) {
ESP_LOGI(TAG, "cnt: %d\n", cnt++);
vTaskDelay(1000 / portTICK_RATE_MS);
gpio_set_level(GPIO_OUTPUT_IO_0, cnt % 2);
gpio_set_level(GPIO_OUTPUT_IO_1, cnt % 2);
}
}
Please if anybody could help me make sense of this whole code also. Thank you so much in advance!
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!
How I could have 2 interrupts with one handler by this code below:
SYSCFG->EXTICR[0] |= SYSCFG_EXTICR1_EXTI0_PB | SYSCFG_EXTICR1_EXTI1_PC;
EXTI->IMR = EXTI_IMR_MR0 | EXTI_IMR_MR1;
EXTI->RTSR = EXTI_RTSR_TR0| EXTI_RTSR_TR1;
/* Configure NVIC for External Interrupt */
/* (6) Enable Interrupt on EXTI0_1 */
/* (7) Set priority for EXTI0_1 */
NVIC_EnableIRQ(EXTI0_1_IRQn); /* (6) */
NVIC_SetPriority(EXTI0_1_IRQn,0); /* (7) */
This is the code that the handler excecute:
void EXTI0_1_IRQHandler(void)
{
if ((EXTI->PR & EXTI_PR_PR1) == EXTI_PR_PR1) /* Check line 1 has triggered the IT */
{
EXTI->PR = EXTI_PR_PR1; /* Clear the pending bit */
GPIOC->ODR |= 1<<0;
}
if ((EXTI->PR & EXTI_PR_PR0) == EXTI_PR_PR0) /* Check line 0 has triggered the IT */
{
EXTI->PR = EXTI_PR_PR0; /* Clear the pending bit */
GPIOC->ODR &= ~(1<<0);
}
}
The code works fine when I click on the button that is connected to PC1, the LED turns on and when I click on the button that is connected to PB0 the LED turns off.
In my if structures I check which line is active but I also want the LED only turns on by clicking on PC1 and not with a click on another pin on line 1, the same for line 0 but I don't know how I can change the conditions for the if structures.
The micro-controller is a STM32F091.
First: you can't connect more than one pin (A..Fx) per EXTIx line (see RM0091 page 177). So EXTI line 0 IRQ is strictly correspond to one pin: C0 in your code.
Second: don't use IRQs for serve buttons. You must implement bounce filter and best idea for this is check button's pin state by timer. Human reaction is about 200ms, really pushed button will produce pulse with duration 100-200ms. So you need timer with 12-24ms and two bytes in RAM for each button... See code example bellow:
uint8_t btn_state = (uint8_t)0x0, btn_mask = (uint8_t)0x1;
void some_tim_irq_handler(void)
{
if (GPIOC->IDR & (uint16_t)0x1) { // PC0 up
btn_state |= btn_mask;
} else { // PC0 down
btn_state &= (uint8_t)~btn_mask;
}
btn_mask <<= (uint8_t)0x1; // mask cycle
if (btn_state == (uint8_t)0x0) {
// One state
return;
}
if (btn_state == (uint8_t)0xFF) {
// Second state
}
}
I'm using PIC32MX575F256L microcontroller. This is a simple program to turn on and turn of LED's connected to lower 8 bits of port A using a simple switch as external interrupt:
#include<p32xxxx.h>
#include<plib.h>
void __ISR(3,ipl4) EXTInterrupthandller(void) // interrupt handler
{
PORTAINV = 0x0ff; //toggle lower 8 bits of port A (LEDs)
IFS0CLR = 0x00000800; //clear the interrupt flag
}
main()
{
DDPCONbits.JTAGEN = 0;
TRISA= 0; // set port A as output port
TRISESET = 0x0200; // set external interrupt pin as input pin
PORTA = 0; // initially LEDs are off
IEC0CLR = 0x00000800; // disable INT3
IPC0SET = 0x10000000; // set priority and sub priority of interrupt
INTCONCLR = 0x00000004; // clear the bit for falling edge trigger
IFS0CLR = 0x00000800; // clear the interrupt flag
INTEnableSystemSingleVectoredInt(); // configure system to handle single vector interrupts
IEC0SET = 0x00000800; // enable INT3
while(1); // main loop
}