Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
What is the difference between HAL_Delay() function and an empty for-loop? Timer should create interrupt and switch off LED.
If I use HAL_Delay() in interrupt function the result is that LED is off forever:
void TIM6_DAC_IRQHandler() {
HAL_TIM_IRQHandler(&htim6);
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
HAL_Delay(125);
}
But if I use instead:
void TIM6_DAC_IRQHandler() {
HAL_TIM_IRQHandler(&htim6);
HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
for (int i=0; i<1000000; i++);
}
then LED1, which is always on in main-file, is set off for short time and then on, as I expect.
So why the code with HAL_Delay does not work?
The rule of thumb: NEVER USE DELAYS in the interrupt handlers.
HAL_Delay uses SysTick interrupt and if the priority of SysTick is lower than the priority of the interrupt in which handler it is called, will end up in the dead loop as SysTick Handler will be never invoked.
empty loop:
I would personally advice to use another forms of the loops:
for(volatile count = 0; count < 1000; count++);
or
for(count = 0; count < 1000; count++) asm("");
https://godbolt.org/z/hY117n
Related
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
I work with atmega16, in both side master and slave.
I want to send a number between 100-999 that entered by keypad to the slave.
Numbers are 16 bit, but spdr register is 8 bit, so I send first lsb then msb bits. This works well and I send my number correctly.
But my problem is in slave side:
I enabled interrupt spie in slave side so each spdr received from master took as a interrupt and goes to ISR function. But because of my number is 16 bit, I want to take each 16 bit or two byte as a interrupt. What should i do?
You know your message length (16 bit or 2 byte). Just create a ring buffer to store two bytes and fill the ring buffer. Maybe you can add a third byte as start or end byte or something else but this is up to you. Additional you set a flag if your transmission ends.
So your code can look like this. Note this code is only the ISR and for an XMega as SPI slave but it should help to understand the procedure.
#define SPI_BUFFER_SIZE 2
uint8_t SPI_RxSlaveBuffer[SPI_BUFFER_SIZE];
typedef struct
{
uint8_t* RxBuffer;
uint8_t BytesProcessed;
uint8_t Status;
} SPI_Buffer_t;
static SPI_Buffer_t SlaveBuffer;
int main()
{
// Some code
SlaveBuffer.RxBuffer = SPI_RxSlaveBuffer;
// Some other code
}
ISR(SPIC_INT_vect)
{
SlaveBuffer.RxBuffer[SlaveBuffer.BytesProcessed++] = SPIC.DATA;
if(SlaveBuffer.BytesProcessed >= SPI_BUFFER_SIZE - 1)
{
SlaveBuffer.BytesProcessed = 0x00;
SlaveBuffer.Status = 0x01;
}
}
You can also check the state of the SS pin and reset the counter if the pin is asserted by the master (in case that the master has aborted the transmission or something else) - for example with polling the SS pin or wiring the signal of the SS pin to an interrupt pin to generate an additional I/O interrupt.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I would like to use a dsPIC33EP32MC204 microcontroller for motor control application. However I am unable to make the High-Speed PWM work (no PWM pulses on the PWM2H pin), even though i was following the User Manual and the Family Reference Manual. Here is my code:
void Init_PWM(void)
{
PTCONbits.PTEN = 0; //PWM module is disabled
PTCONbits.PTSIDL = 0; // PWMx time base runs in CPU Idle mode
PWMCON2bits.FLTIEN = 0; // Fault interrupt is disabled and the FLTSTAT bit is cleared
PWMCON2bits.ITB = 0; // PTPER register provides timing for this PWM generator
PWMCON2bits.MDCS = 0; // PDCx register provides duty cycle information for this PWM generator
PWMCON2bits.MTBS = 0; // PWM generator uses the primary master time base for synchronization and as the clock source
PWMCON2bits.IUE = 0; // Updates to the active PDCx registers are synchronized to the PWMx period boundary
PTCON2bits.PCLKDIV = 0b000; // PWM Input Clock Prescaler
PWMCON2bits.CAM = 0; // Edge Aligned PWM
PWMCON2bits.DTC = 0b10; // Dead time function is disabled
IOCON2bits.PENH = 1; // PWMx module controls PWMxH pin
IOCON2bits.POLH = 0; // PWMxH pin is active-high
IOCON2bits.OVRENH = 0; // PWMx generator controls PWMxH pin
IOCON2bits.PMOD = 0b01; // PWM I/O pin pair is in Redundant Output mode
PHASE2 = 0; // No Phase Shift
PTPER = 0x4E20; // Period register
PTCONbits.PTEN = 1; //PWM module is enabled
}
Related code from the main() function:
TRISBbits.TRISB12 = 0;
Init_PWM();
PDC2 = 0x2710; //Duty Cycle
I would be grateful if someone could tell me why can't I see any PWM pulses after completing the attached configurations. What am I doing wrong? Thank you!
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I'm working on a project part of it to have some reads with ultrasonic sensor and send it with serial communication, i wrote code and it gives random reads and sometimes gives 0 as a read, is the formula i used for finding distance right !?, or there is another formula, I'm using Atmega32 with internal 8MHz clock, can someone help me and know what's wrong with my code !?.
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
void inti_serial();
static volatile int pulse = 0;
static volatile int change = 0;
int main(void)
{
/* Replace with your application code */
inti_serial();
MCUCR |= (1 << ISC00); //Any logical change on INT0
GICR |= (1 << INT0); //Enable INT0
TCCR1A=0;
sei();
while (1)
{
PORTC |= (1<<0);
_delay_us(15);
PORTC &= ~(1<<0);
while(!(UCSRA & (1<<UDRE)));
UDR = ((pulse/2)*1*(1/F_CPU)*343) ;
_delay_ms(100);
}
}
ISR(INT0_vect){
if (change==1)//when logic from HIGH to LOW
{
TCCR1B=0;//disabling counter
pulse=TCNT1;//count memory is updated to integer
TCNT1=0;//resetting the counter memory
change=0;
}
if (change==0)//when logic change from LOW to HIGH
{
TCCR1B|=(1<<CS10);//enabling counter
change=1;
}
}
void inti_serial()
{
UCSRB |= (1<<TXEN);
UCSRC |= (1<<UCSZ0) | (1<<UCSZ1) | (1<<URSEL);
UBRRL = 0x33;
}
I see a few options for improvement in your development:
You are writing a sample from the ISR to variable and you read it continuously from the main loop and output it. Instead you should only output a new sample once (makes the serial data much smaller and easier to concentrate on the actual content and sample timing)
Before you think about the correct formula you should verify that your sampling mechanism is right. Without details about your sensor, nobody here can judge your formula, anyway.
Instead of sampling a free running counter you could use the input capture circuit of the processor (more accurate, less jitter due to interrupt latency)
Instead of resetting the counter register to zero you could subtract two consecutive samples from each other (less sample jitter due to interrupt latency)
Instead of deducing the edge from a toggled flag, ask the hardware about the state of the pin or which edge triggered the interrupt (or the capture)
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I´m new in Arm microcontroller programming. I read the datasheet and found this :
Reset/initialize.
Write 1 to CR[INTM], CR[HA], and CR[GO]
Poll SR[OREG_LVL] until it is not 0.
When SR[OREG_LVL] is not 0, read the available random data from
OR[RANDOUT]
Repeat steps 3 and 4 as needed.
These are the steps for generating random numbers. Could someone give me a code example ? I'm working with the k64 sub-family, specifically MK64FX512VLL12.
Here's what I've tried:
void Rng_Test()
{
RNG->CR |= RNG_CR_SLP_MASK;
RNG->CR |= RNG_CR_GO_MASK;
RNG->CR |= RNG_CR_HA_MASK;
RNG->CR |= RNG_CR_INTM_MASK;
while (RNG_SR_OREG_LVL_MASK == 0) { }
}
Using the code you already have
void Rng_Init() {
RNG->CR |= RNG_CR_SLP_MASK;
RNG->CR |= RNG_CR_GO_MASK;
RNG->CR |= RNG_CR_HA_MASK;
RNG->CR |= RNG_CR_INTM_MASK;
}
int Rng_GetRand() {
while ((RNG->SR & RNG_SR_OREG_LVL_MASK) == 0);
return RNG->OR;
}
Something like the above should work, Rng_Init() is required once, Rng_GetRand should return a new random number (not necessarily different) each time it's called.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
Is it possible to do bitwise operations directly on a long piece of memory (say, 512 bit or even more)?
By directly I mean, NOT multiple shifting and watching bounds... as following code.
/*
// shifting 128 bit data [pc2, pc1] to left,
// and then assigning it to [rc2, rc1]:
*/
uint64_t au1, pc1, pc2, rc1, rc2;
rc1 = pc1 >> 63;\
au1 = pc2 << 1;\
rc2 = rc1 ^ au1;\
rc1 = pc1 << 1;\