I'm experiencing an odd issue with a Nucleo L432KC devboard from ST. When I start the IWDG using the following code:
IWDG_HandleTypeDef IwdgHandle;
IwdgHandle.Instance = IWDG;
IwdgHandle.Init.Prescaler = IWDG_PRESCALER_256;
IwdgHandle.Init.Reload = 30 * 125;
// 30 sec * 125 watchdog pulses per sec using the LSI frequency of ~32kHz and prescaler 256
and then try to "pet" the watchdog using the following:
HAL_IWDG_Refresh(&IwdgHandle); // resets the IWDG counter back to value of reload
The device immediately resets and the RCC_FLAG_IWDGRST is set, indicating the reset was due to the watchdog timeout.
This issue using the same code worked perfectly on a Nucleo L152RE (the only difference is the dependencies now are for the L4xx series instead of L1xx)
Any ideas on why this reset is occuring?
Independent watchdog in the Stm32L4 series have window option. When enabled, it will reset the mcu if watchdog is reloaded too early - when watchdog counter value is above the window value.
IwdgHandle.Init.Window should be set at 0xFFF (max value) if option is not required. If you have IwdgHandle declared in bss - Window field will be zero, resulting in a reset on watchdog refresh if counter is above zero.
typedef struct
{
uint32_t Prescaler; /*!< Select the prescaler of the IWDG.
This parameter can be a value of #ref IWDG_Prescaler */
uint32_t Reload; /*!< Specifies the IWDG down-counter reload value.
This parameter must be a number between Min_Data = 0 and Max_Data = 0x0FFF */
uint32_t Window; /*!< Specifies the window value to be compared to the down-counter.
This parameter must be a number between Min_Data = 0 and Max_Data = 0x0FFF */
} IWDG_InitTypeDef;
PS: Watchdog's timer is a downcounter. HAL_IWDG_Refresh reloads counter with Reload value, not resets to zero
Related
Is it possible to unreset some GPIO pins while using NVIC_SystemReset function at STM32 ?
Thanks in advance for your answers
Best Regards
I try to reach NVIC_SystemReset function. But not clear inside of this function.
Also this project is running on KEIL
Looks like it is not possible, NVIC_SystemReset issues a general reset of all subsystems.
But probably, instead of system reset, you can just reset all peripheral expect one you need keep working, using peripheral reset registers in Reset and Clock Control module (RCC): RCC_AHB1RSTR, RCC_AHB2RSTR, RCC_APB1RSTR, RCC_APB1RSTR.
Example:
// Issue reset of SPI2, SPI3, I2C1, I2C2, I2C3 on APB1 bus
RCC->APB1RSTR = RCC_APB1RSTR_I2C3RST | RCC_APB1RSTR_I2C2RST | RCC_APB1RSTR_I2C1RST
| RCC_APB1RSTR_SPI3RST | RCC_APB1RSTR_SPI2RST;
__DMB(); // Data memory barrier
RCC->APB1RSTR = 0; // deassert all reset signals
See detailed information in RCC registers description in Reference Manual for your MCU.
You may also need to disable all interrupts in NVIC:
for (int i = 0 ; i < 8 ; i++) NVIC->ICER[i] = 0xFFFFFFFFUL; // disable all interrupts
for (int i = 0 ; i < 8 ; i++) NVIC->ICPR[i] = 0xFFFFFFFFUL; // clear all pending flags
if you want to restart the program, you can reload stack pointer to its top value, located at offset 0 of the flash memory and jump to the start address which is stored at offset 4. Note: flash memory is addressed starting from 0x08000000 address in the address space.
uint32_t stack_top = *((volatile uint32_t*)FLASH_BASE);
uint32_t entry_point = *((volatile uint32_t*)(FLASH_BASE + 4));
__set_MSP(stack_top); // set stack top
__ASM volatile ("BX %0" : : "r" (entry_point | 1) ); // jump to the entry point with bit 1 set
Right now it seems that on every click tick, the running process is preempted and forced to yield the processor, I have thoroughly investigated the code-base and the only relevant part of the code to process preemption is below (in trap.c):
// Force process to give up CPU on clock tick.
// If interrupts were on while locks held, would need to check nlock.
if(myproc() && myproc() -> state == RUNNING && tf -> trapno == T_IRQ0 + IRQ_TIMER)
yield();
I guess that timing is specified in T_IRQ0 + IRQ_TIMER, but I can't figure out how these two can be modified, these two are specified in trap.h:
#define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ
#define IRQ_TIMER 0
I wonder how I can change the default RR scheduling time-slice (which is right now 1 clock tick, fir example make it 10 clock-tick)?
If you want a process to be executed more time than the others, you can allow it more timeslices, *without` changing the timeslice duration.
To do so, you can add some extra_slice and current_slice in struct proc and modify the TIMER trap handler this way:
if(myproc() && myproc()->state == RUNNING &&
tf->trapno == T_IRQ0+IRQ_TIMER)
{
int current = myproc()->current_slice;
if ( current )
myproc()->current_slice = current - 1;
else
yield();
}
Then you just have to create a syscall to set extra_slice and modify the scheduler function to reset current_slice to extra_slice at process wakeup:
// Switch to chosen process. It is the process's job
// to release ptable.lock and then reacquire it
// before jumping back to us.
c->proc = p;
switchuvm(p);
p->state = RUNNING;
p->current_slice = p->extra_slice
You can read lapic.c file:
lapicinit(void)
{
....
// The timer repeatedly counts down at bus frequency
// from lapic[TICR] and then issues an interrupt.
// If xv6 cared more about precise timekeeping,
// TICR would be calibrated using an external time source.
lapicw(TDCR, X1);
lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER));
lapicw(TICR, 10000000);
So, if you want the timer interrupt to be more spaced, change the TICR value:
lapicw(TICR, 10000000); //10 000 000
can become
lapicw(TICR, 100000000); //100 000 000
Warning, TICR references a 32bits unsigned counter, do not go over 4 294 967 295 (0xFFFFFFFF)
Right now it seems that on every click tick, the running process is preempted and forced to yield the processor, I have thoroughly investigated the code-base and the only relevant part of the code to process preemption is below (in trap.c):
// Force process to give up CPU on clock tick.
// If interrupts were on while locks held, would need to check nlock.
if(myproc() && myproc() -> state == RUNNING && tf -> trapno == T_IRQ0 + IRQ_TIMER)
yield();
I guess that timing is specified in T_IRQ0 + IRQ_TIMER, but I can't figure out how these two can be modified, these two are specified in trap.h:
#define T_IRQ0 32 // IRQ 0 corresponds to int T_IRQ
#define IRQ_TIMER 0
I wonder how I can change the default RR scheduling time-slice (which is right now 1 clock tick, fir example make it 10 clock-tick)?
If you want a process to be executed more time than the others, you can allow it more timeslices, *without` changing the timeslice duration.
To do so, you can add some extra_slice and current_slice in struct proc and modify the TIMER trap handler this way:
if(myproc() && myproc()->state == RUNNING &&
tf->trapno == T_IRQ0+IRQ_TIMER)
{
int current = myproc()->current_slice;
if ( current )
myproc()->current_slice = current - 1;
else
yield();
}
Then you just have to create a syscall to set extra_slice and modify the scheduler function to reset current_slice to extra_slice at process wakeup:
// Switch to chosen process. It is the process's job
// to release ptable.lock and then reacquire it
// before jumping back to us.
c->proc = p;
switchuvm(p);
p->state = RUNNING;
p->current_slice = p->extra_slice
You can read lapic.c file:
lapicinit(void)
{
....
// The timer repeatedly counts down at bus frequency
// from lapic[TICR] and then issues an interrupt.
// If xv6 cared more about precise timekeeping,
// TICR would be calibrated using an external time source.
lapicw(TDCR, X1);
lapicw(TIMER, PERIODIC | (T_IRQ0 + IRQ_TIMER));
lapicw(TICR, 10000000);
So, if you want the timer interrupt to be more spaced, change the TICR value:
lapicw(TICR, 10000000); //10 000 000
can become
lapicw(TICR, 100000000); //100 000 000
Warning, TICR references a 32bits unsigned counter, do not go over 4 294 967 295 (0xFFFFFFFF)
I'm trying to set up an interrupt-handler in my driver for DM6446 GPIO BANK 0 interrupt.But request_irq returns -22.I know the Interrupt number for GPIO BANK-0 from the data sheet which states it to be 56.Following are the settings for GPIO in my code.I want to get interrupt on GPIO-10.
while((REG_VAL(PTSTAT) & 0x1) != 0); // Wait for power state transtion to finish
REG_VAL(MDCTL26) = 0x00000203; //To enable GPIO module and EMURSITE BIT as stated in sprue14 for state transition
REG_VAL(PTCMD) = 0x1; // Start power state transition for ALWAYSON
while((REG_VAL(PTSTAT) & 0x1) != 0); // Wait for power state transtion to finish
REG_VAL(PINMUX0) = REG_VAL(PINMUX0) & 0x80000000; //Disbale other Functionlaity on BANK 0 pins
printk(KERN_DEBUG "I2C: PINMUX0 = %x\n",REG_VAL(PINMUX0));
REG_VAL(DIR01) = REG_VAL(DIR01) | 0xFFFFFFFF; //Set direction as input for GPIO 0 and 10
REG_VAL(BINTEN) = REG_VAL(BINTEN) | 0x00000001; //Enable Interrupt for GPIO Bank 0
REG_VAL(SET_RIS_TRIG01) = REG_VAL(SET_RIS_TRIG01) | 0x00000401; // Enable rising edge interrupt of GPIO BANK 0 PIN 0 PIN 10
REG_VAL(CLR_FAL_TRIG01) = REG_VAL(CLR_FAL_TRIG01) | 0x00000401; // Disable falling edge interrupt of Bank 0
Result = request_irq(56,Gpio_Interrupt_Handler,0,"gpio",I2C_MAJOR);
if(Result < 0)
{
printk(KERN_ALERT "UNABLE TO REQUEST GPIO IRQ %d ",Result);
}
A little help shall be appreciated.
Thank you.
I have tried the gpio_to_irq as well for PIN-10 of BANK-0 but it returns irq no to be 72 but DM6446 has interrupt number upto 63 only in Data sheet.
I got it. If i use gpio_to_irq, It will return a valid IRQ number but different than the interrupt number(which i guess is also called IRQ number) specified in data sheet of Processor.If I see the /proc/interrupts, it will have an entry of that IRQ returned form gpio_to_irq but under GPIO type not the processor's Interrupt controller, which in my case for ARM shall be AINTC.All other interrupts are of AINTC type.
Moreover, Even if request_irq succeeds with interrupt number stated in data sheet,/proc/stat will report interrupts at both IRQ numbers i.e. AINTC and GPIO type.
I am writting firmware for stm32f072.
The problem is that SysTick interrupt doesn't happens.
Here is simple code for SysTick configuring:
SysTick_Config(1000);
This function is taken from CMSIS's core_cm0.h file:
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
if ((ticks - 1) > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Systick Interrupt */
SysTick->VAL = 0; /* Load the SysTick Counter Value */
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
return (0); /* Function successful */
}
System timer counts as expected.
SysTick->CTRL's overcounting bit is set to 1 but there is no interrupt happens! Firmware doesn't jump to SysTick_Handler().
What I miss? This code is enough for stm32f1 and stm32f4 devices but not work for stm32f0.
I recommend you to take a look at the Code Snippets from ST. These are low level programs for F0 (and L0) families. Some of them use the SysTick (e.g. first two example from CLOCK CONTROLLER projects) and all things are preconfigured and hopefully works on your board too. It is written originally for the STM32F072 Discovery board. I used it with my custom board with some tiny modifications.