I am working on a board which comprises LPC1768 microcontroller. All I want to do is to create an accurate time delay using osdelay function of CMSIS RTOS API. I have set my systick time tick count to 10000.But when I use osdelay(1000) in my thread, it doesn't creates delay period of 1 second as it should do !
Here is the source code
#include"cmsis_os.h"
#include"lpc17xx.h"
void Thread1 (void const *argument) {
while (1) {
LPC_GPIO2->FIOPIN = 0x00000001;
osDelay(1000);
LPC_GPIO2->FIOPIN = 0x00000000;
osDelay(1000);
}
}
osThreadId main_ID,led_ID1,led_ID2;
osThreadDef(Thread1,osPriorityNormal, 1, 0);
int main (void)
{
SystemInit();
LPC_PINCON->PINSEL4 = 0x00000000;
LPC_GPIO2->FIODIR = 0xffffffff;
osKernelInitialize ();
led_ID1 = osThreadCreate(osThread(Thread1), NULL);
osKernelStart ();
}
Now, my problem is with osdelay(1000) not providing a delay of 1000ms as it should do with systick timer tick value set to 1000.
Related
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
I have old programmable timer/ counter (PD71054 - count rate is set to 3Mhz), and now I would like to program a timer in STM32 (STM32F103RET6) to replace PD71054. I need to measure the duration of the square wave (PA0 pin), I found information about on of timer function - capture, but I do not know how to use it. And unfortunately I did't find good examples how to use it (SPL library). I tried to checking the edges of the signal. If a rising edge is detected, TIM5 will be started, if a falling edge is detected TIM5 will be stopped and the counted value will be saved. But I don’t know if this solution is good and how to set an interrupt for both edges of signal and have two different functions to handle for each of the slopes. signal example
int main(void)
{
TIM5_Config();
NVIC_Config ();
//IWDG_ReloadCounter();
RCC_Config();
RCC_APB1PeriphClockCmd(RCC_APB1PeriphClockCmd, ENABLE);
while(1){
}
}
RCC_Config()
{
BKP_DeInit();
// Reset RCC
RCC_DeInit ();
// HSI ON
RCC_HSICmd(ENABLE);
// Wait for HSI
while(RCC_GetFlagStatus(RCC_FLAG_HSIRDY) == RESET){};
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div1);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_SYSCLKConfig(RCC_SYSCLKSource_HSI);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}
void IWDG_Config (void) {
// watchdoga IWGD
IWDG_WriteAccessCmd (IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(IWDG_Prescaler_4); // 40kHz/4 = 10kHz
IWDG_SetReload(0x28A); // 65ms
IWDG_Enable(); // Start IWDG oraz LSI
}
void TIM5_IRQHandler(void)
{
TIM_Cmd(TIM5, ENABLE);
}
void TIM5_Config (void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);
// Ustawienia podstawy czasu TIM5
TIM_TimeBaseStructure.TIM_Period= 0xFFFF; //65535
TIM_TimeBaseStructure.TIM_Prescaler = 23; // fclk = 72MHz/24 =okolo 3MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);
// Zrodlo przerwania kanal 1
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);
TIM_Cmd(TIM5,ENABLE);
// TIM5_CH1, Rising edge, no filter
TIM_TIxExternalClockConfig(TIM5, TIM_TIxExternalCLK1Source_TI1, TIM_ICPolarity_Rising, 0x00);
TIM5_ICInitStructure.TIM_Channel=TIM_Channel_1;
TIM5_ICInitStructure.TIM_ICFilter=0;
TIM5_ICInitStructure.TIM_ICPolarity=TIM_ICPolarity_Rising;
TIM5_ICInitStructure.TIM_ICPrescaler=TIM_ICPSC_DIV1;
TIM5_ICInitStructure.TIM_ICSelection=TIM_ICSelection_DirectTI;
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
}
void NVIC_Config (void)
{
NVIC_InitStructure.NVIC_IRQChannel=TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
Sorry I dont have time to go into details about TIMER capture methods.I can offer easer way to do this, at least you can try. Set PA0 pin as EXTI on rising, falling edges. So IRQ will be generated on rising and falling edges. Also setup TIM1 or TIM2 , basically 32bit timer with needed precision, just start timer and its counter. So at rising edge, you can easily reset timer TIM1->CNT = 0 it will be your start time when SIGNAL rise. And then when falling edge appear fetch TIM->CNT . Thats all. Just don't forget to control extra flags (own created variables) wich will help to separate rising and falling edges. Also you could even count those pulses in those events, but its not reliable way.
This is only a snippet, abstract, it should help to understand an idea.
void enable_timer(void){
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
TIM_TimeBaseInitTypeDef timerInitStructure;
timerInitStructure.TIM_Prescaler = 48;
timerInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
timerInitStructure.TIM_Period = 0xFFFFFFFF; //32 bit timer , precision 1us
timerInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM1, &timerInitStructure);
TIM_Cmd(TIM1, ENABLE);
}
EXTI handler:
void EXTI0_1_IRQHandler (void)
{
if (EXTI_GetITStatus(EXTI_LINE0) != RESET){
EXTI_ClearITPendingBit(EXTI_LINE0); //clear the irq flag
if(rising_edge)
TIM1->CNT = 0;
if(falling_edge)
fetcher = TIM1->CNT; // here you get your pulse duration time in us
}
}
I want to configure timer1 of PIC24F16KA102 to count it. The clock source must be the internal clock of 8 MHz. I configured the register T1CON and set on high level the bit TON to start the timer. Timer1 is set to go in overflow every 100 us, then with a while cycle I wille increase the variable count. I'am not understanding because timer1 don't work, I observed that it does not increase. Why?
#include <xc.h>
#include "config.h"
int count = 0;
void main(void) {
TRISB = 0;
T1CON = 0; //TRM1 stopped, internal clock source, prescaler 1:1
_TON = 1;
TMR1 = 65135; //overflow of TM1 every 100 us (400 counts)
while (1) {
if (TMR1 == 65535) {
count++; // increase every 100 us
TMR1 = 65135;
}
}
}
Try setting the Timer 1 period register (PR1) and using an interrupt rather than trying to catch and reload TMR1 on its final count. You're trying to catch TMR1 on EXACTLY 65535, and that will almost never work because once TMR1 hits 65535, it's just going to overflow and begin counting from 0 again.
EDIT: Of course, this assumes it counts at all. I don't know what the behavior of a timer is when you leave the period register at 0. It may simply count to it's maximum of 65535 then reset to 0, or it may never count at all and continuously load PRx into TMRx since they match at 0
PRx is meant to define the period you want for a given timer, in this case 100uS. PR1 = 400. Once TMR1 = PR1, the timer will reset itself automatically and raise an interrupt to alert you that the timer has elapsed.
volatile unsigned int count = 0; //Vars that change in an ISR should be volatile
PR1 = 400; //Set Period for Timer1 (100us)
T1CON = 0x8000; //Enable Timer1
IEC0bits.T1IE = 1; //Enable Timer1 Interrupt
IPC0bits.T1IP = 0b011;
Pair this with an ISR function to increment count whenever the timer elapses:
void __attribute__ ((interrupt,no_auto_psv)) _T1Interrupt (void)
{
count++;
IFS0bits.T1IF = 0; //Make sure to clear the interrupt flag
}
You could also try something like this without any interrupts:
void main(void){
unsigned int count = 0;
TMR1 = 0;
T1CON = 0x8000; //TON = 1
while(1){
if (TMR1 >= 400){
count++;
TMR1=0;
}
}
}
However I would recommend using the PR register and an ISR. This is what it's meant to do.
EDIT: I would also recommend reading the PIC24F Reference Manual on timers:
Here
Im trying to create an embedded c code to control a dc motor with the PIC32MX460F512L microcontroller. Ive Configured the system clock at 80MHz, and the peripheral clock at 10MHz, Am using Timer 1 for pulsing the PWM with a given duty cycle, and Timer 2 for measuring the motor run time. I have a header file(includes.h) that contains system configuration information eg clock. Ive created most of the functions but some are a bit challenging. For example, initializing the LEDS and the functions for forward, backward movements and stop, I wanted the dc motor to run in forward direction for 4 sec at 70% duty cycle, then stop for 1 sec then reverse for 3 sec at 50% duty cycle and then stop for 1 sec and then forward again for 3 sec at 40% duty cycle, stop for 1 sec and finally forward for 5 sec at 20% duty cycle. Any suggestions for the forward, stop, and reverse functions
#include <stdio.h>
#include <stdlib.h>
#include <includes.h>
void main()
{
// Setting up PIC modules such as Timers, IOs OCs,Interrupts, ...
InitializeIO();
InitializeLEDs();
InitializeTimers();
while(1) {
WaitOnBtn1();
Forward(4.0,70);
Stop(1.0);
Backward(3.0,50);
Stop(2);
Forward(3.0,40);
Stop(1.0);
Backward(2.0,20);
LEDsOFF();
}
return;
}
void InitializeIO(){
TRISAbits.TRISA6 = 1;
TRISAbits.TRISA7 = 1;
TRISGbits.TRISG12 = 0;
TRISGbits.TRISB13 = 0;
LATGbits.LATB12 = 0;
LATGbits.LATB13 = 0;
return;
}
void InitializeLEDs(){
//code to initialize LEDS
}
void InitializeTimers(){
// Initialize Timer1
T1CON = 0x0000; // Set Timer1 Control to zeros
T1CONbits.TCKPS=3; // prescale by 256
T1CONbits.ON = 1; // Turn on Timer
PR1= 0xFFFF; // Period of Timer1 to be full
TMR1 = 0; // Initialize Timer1 to zero
// Initialize Timer2
T2CON = 0;
T2CONbits.TCKPS = 7; // prescale by 256
T2CONbits.T32 = 1; // use 32 bits timer
T2CONbits.ON = 1;
PR2 = 0xFFFFFFFF; // Period is set for 32 bits
TMR2 = 0;
}
void WaitOnBtn1(){
// wait on Btn1 indefinitely
while(PORTAbits.RA6 == 0);
// Turn On LED1 indicating it is Btn1 is Pushed
LATBbits.LATB10 = 1;
return;
}
void Forward(float Sec, int D){
int RunTime = (int)(Sec*39000); // convert the total
time to number of Tics
TMR2 = 0;
//LEDs
LATGbits.LATG12 = 1; // forward Direction
LATBbits.LATB12 = 0;
LATBbits.LATB13 = 0;
LATBbits.LATB11 = 1;
// Keep on firing the PWM as long as Run time is not
elapsed
while (TMR2 < RunTime){
PWM(D);
}
return;
}
void PWM(int D){
TMR1 = 0;
int Period = 400;
while (TMR1< Period) {
if (TMR1 < Period*D/100){
LATGbits.LATG13 = 1;
}
else{
LATGbits.LATG13 = 0;
}
}
Functions, not methods, to be precise.
So what is exactly the question?
What I can say from a quick look on a source code:
LEDs initialisation should be done as you did in InitializeIO() function. Simply set proper TRISx bits to 0 to configure LED pins as output.
For the PWM and motor control functions you should take some time and try to understand how builtin PWM peripheral works. It is a part of OC (Output Compare) and it is very easy to use. Please, take look on following link http://ww1.microchip.com/downloads/en/DeviceDoc/61111E.pdf
and this one for the minimal implementation using builtin peripheral libraries https://electronics.stackexchange.com/questions/69232/pic32-pwm-minimal-example
Basically you need to set up OC registers to "make" OC module acts like PWM. You need to allocate one of the timers to work with OC module (it will be used for base PWM frequency) and that's it.
All you need after that is to set PWM duty cycle value by setting timer PRx register, you don't need to swap bits like in your PWM routine.
To stop it simple stop it simply disable the timer.
To run it again run the timer.
To change direction (it depends of your driver for the motor) I guess you need just to toggle direction pin.
I hope it helps...
first code:
//------------------------------------------------------------------------------
/// Interrupt handlers for TC interrupts. Toggles the state of LEDs
//------------------------------------------------------------------------------
char token = 0;
void TC0_IrqHandler(void) {
volatile unsigned int dummy;
dummy = AT91C_BASE_TC0->TC_SR;
if(token == 1) {
PIO_Clear(&leds[0]);
PIO_Set(&leds[1]);
token = 0;
}
else {
PIO_Set(&leds[0]);
PIO_Clear(&leds[1]);
token = 1;
}
}
//------------------------------------------------------------------------------
/// Configure Timer Counter 0 to generate an interrupt every 250ms.
//------------------------------------------------------------------------------
void ConfigureTc(void) {
unsigned int div;
unsigned int tcclks;
AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_TC0; // Enable peripheral clock
TC_FindMckDivisor(1, BOARD_MCK, &div, &tcclks); // Configure TC for a 4Hz frequency and trigger on RC compare
TC_Configure(AT91C_BASE_TC0, tcclks | AT91C_TC_CPCTRG);
AT91C_BASE_TC0->TC_RC = (BOARD_MCK / div) / 1; // timerFreq / desiredFreq
IRQ_ConfigureIT(AT91C_ID_TC0, 0, TC0_IrqHandler); // Configure and enable interrupt on RC compare
AT91C_BASE_TC0->TC_IER = AT91C_TC_CPCS;
IRQ_EnableIT(AT91C_ID_TC0);
printf(" -- timer has started \n\r");
TC_Start(AT91C_BASE_TC0);
}
it's just interrupt timer and it's event (handler) but when I run some
while(1) {
// action
after ConfigureTc() it both cycle and interrupt timer are freezes... Why could that be? Should I add another timer and avoid while(1) ?
while(1) {
printf("hello");
}
-- this breaks (freeze) loops (yes, if I don't use timer it works as it must)
I'll venture an actual answer here. IME, 99% of the time my boards 'go out' with no response on any input and no 'heartbeat' LED-flash from the low-priority 'blinky' thread, the CPU has flown off to a prefetch or data abort handler. These handlers are entered by interrupt and most library-defined default handlers do not re-enable interrupts, so stuffing the entire system. Often, they're just endless loops and, with interrupts disabled, that's the end of the story:(
I have changed my default handlers to output suitable 'CRITICAL ERROR' messages to the UART, (by polling it - the OS/interrupts are stuft!).