May I ask when setting the value for Timer0 why in some cases people have to use subtraction to represent the preset Timer0 instead of using its result directly (in this case, 175 )? And in this case what is the purpose of the UL suffix?
Examble:
X=255Ul-80;
void interrupt ISR(void)
{
if (T0IF)
{
T0IF=0;
TMR0=X;
abc();
}
}
...
The Microchip documentation describes how the TIMER0 module works.
It does not describe methods of how to use this counter/timer module very well.
The fundamental architecture of the TIMER0 module is very primitive when compared to any modern embedded controller today. It is unclear why Microchip persists with including this counter/timer module in new 8-bit PIC controllers. Understand that 35 years ago it was a challenge to maximize functionality with the minimum number of transistors so that each controller chip would be as small as possible and yield the most chips per wafer.
The way TIMER0 works is as an up counter. When first implemented the controller did not support interrupts at all. See baseline controllers like the PIC12F508. The mid-range controllers like the PIC16F877 added support for interrupts and TIMER0 acquired the functionality to request an interrupt when the 8-bit count register rolled over from 0xFF to 0x00. It takes 256 counts for TIMER0 to assert an interrupt request when the TIMER0 count register starts at 0x00. When the interrupt needs to be asserted after a specific number of counts set the count register to the value of 256-(Specific_Number_Of_Counts) then clear the TIMER0 interrupt request.
This feature is used by developer to have the TIMER0 interrupt request assert after a specific number of counts.
There is an "off-by-one" error in the example in you question:
X=255Ul-80;
As the TIMER0 count register will have the value of 0xFF after 80 counts and the TIMER0 interrupt request will be set after 81 counts.
The example code in your question "suggests" that you want the "abc()" function invoked after TIMER0 have been clocked 80 times. The function will actually be invoked after TIMER0 have been clocked 81 times.
Also note that the simulation model for TIMER0 does not have a cycle accurate implementation so does not simulate the actual accurately. This simulation flaw exists in all releases of MPLABX for 8-bit PIC controllers. Be warned that the simulator will not provide cycle counts that match the real world hardware.
Related
I've got an STM32F4, and I want to PWM a GPIO port that's been OR'd with a mask..
So, maybe we want to PWM 0b00100010 for awhile at 200khz, but then, 10khz later, we now want to PWM 0b00010001...then, 10kHz later, we want to PWM some other mask on the same GPIO.
My question is, how do you do this with DMA? I'm trying to trigger a DMA transfer that will set all the bits on a rising edge, and then another DMA transfer that will clear all the bits on a falling edge.
I haven't found a good way to do this, (at least with CubeMX and my limited experience with C & STM32's) as it looks like I only get a chance to do something on a rising edge.
One of my primary concerns is CPU time, because although I mention hundreds of kilohertz in the above example, I'd like to make this framework very robust in-so-far as it isn't going to be wasteful of CPU resources...That's why I like the DMA idea, since it's dedicated hardware doing the mindless lifting of a word here to a word there type of stuff, and the CPU can do other things like crunch numbers for a PID or something.
Edit
For clarity : I have a set of 6 values that I could write to a GPIO. These are stored in an array.
What I'm trying to do is set up a PWM timer to set the GPIO during the positive width of the PWM and then I want the GPIO to be set to 0b00000000 during the low period width if the pwm.
So, I need to see when the rising edge is, quickly write to the gpio, then see when the falling edge is, and write 0 to the gpio.
Limited solution without DMA
STM32F4 controllers have 12 timers with up to 4 PWM channels each, 32 in total. Some of them can be synchronized to start together, e.g. you can have TIM1 starting TIM2, TIM3, TIM4 and TIM8 simultaneously. That's 20 synchronized PWM outputs. If it's not enough, you can form chains where a slave timer is a master to another, but it'd be quite tricky to keep all of them perfectly synchronized. Not so tricky, if an offset of a few clock cycles is acceptable.
There are several examples in the STM32CubeF4 library example projects section, from which you can puzzle together your setup, look in Projects/*_EVAL/Examples/TIM/*Synchro*.
General solution
A general purpose or an advanced timer (that's all of them except TIM6 and TIM7) can trigger a DMA transfer when the counter reaches the reload value (update event) and when the counter equals any of the compare values (capture/compare event).
The idea is to let DMA write the desired bit pattern to the low (set) half of BSRR on a compare event, and the same bits to the high (reset) half of BSRR on an update event.
There is a problem though, that DMA1 cannot access the AHB bus at all (see Fig. 1 or 2 in the Reference Manual), to which the GPIO registers are connected. Therefore we must use DMA2, and that leaves us with the advanced timers TIM1 or TIM8. Things are further complicated because DMA requests caused by update and compare events from these timers end up on different DMA streams (see Table 43 in the RM). To make it somewhat simpler, we can use DMA 2, Stream 6 or Stream 2, Channel 0, which combine events from 3 timer channels. Instead of using the update event, we can set the compare register on one timer channel to 0.
Set up the DMA stream of the selected timer to
channel 0
single transfer (no burst)
memory data size 16 bit
peripheral data size 16 bit
no memory increment
peripheral address increment
circular mode
memory to peripheral
peripheral flow controller: I don't know, experiment
number of data items 2
peripheral address GPIOx->BSRR
memory address points to the output bit pattern
direct mode
at last, enable the channel.
Now, set up the timer
set the prescaler and generate an update event if required
set the auto reload value to achieve the required frequency
set the compare value of Channel 1 to 0
set the compare value of Channel 2 to the required duty cycle
enable DMA request for both channels
enable compare output on both channels
enable the counter
This way you can control 16 pins with each timer, 32 if using both of them in master-slave mode.
To control even more pins (up to 64) at once, configure the additional DMA streams for channel 4 compare and timer update events, set the number of data items to 1, and use ((uint32_t)&GPIOx->BSRR)+2 as the peripheral address for the update stream.
Channels 2 and 4 can be used as regular PWM outputs, giving you 4 more pins. Maybe Channel 3 too.
You can still use TIM2, TIM3, TIM4, and TIM5 (each can be slaved to TIM1 or TIM8) for 16 more PWM outputs as described in the first part of my post. Maybe TIM9 and TIM12 too, for 4 more, if you can find a suitable master-slave setup.
That's 90 pins toggling at once. Watch out for total current limits.
what PWM 0b00100010 means? PWM is a square wave with some duty ratio. it wil be very difficult to archive using DMA but you will need to have table with already calculated values. For example to have 2kHz PWM with 10% ratio you will need to have 10 samples one with bit set, nine with bit zeroed. You configure the timer to 20k / sec trigger mem-to-mem (GPIO has to be done this way) DMA transmission in the circular mode. On the pin you will have 2kHz 10% wave. The PWM resolution will be 10%. If you want to make it 0.5% you will need 200 samples table and DMA triggered 400k times per second.
IMO it is better to use timer and DMA to load new values to it (read about the burst DMA mode in the timer documentation in the Reference Manual)
I am trying to write a small driver program on a Beaglebone Black that needs to send a signal with timings like this:
I need to send 360 bits of information. I'm wondering if I can turn off all interrupts on the board for a duration of 500µs while I send the signal. I have no idea if I can just turn off all the interrupts like that. Searches have been unkind to me so far. Any ideas how I might achieve this? I do have some prototypes in assembly language for the signal, but I'm pretty sure its being broken by interrupts.
So for example, I'm hoping I could have something like this:
disable_irq();
/* asm code to send my bytes */
reenable_irq();
What would the bodies of disable_irq() and reenable_irq() look like?
The calls you would want to use are local_irq_disable() and local_irq_enable() to disable & enable IRQs locally on the current CPU. This also has the effect of disabling all preemption on the CPU.
Now lets talk about your general approach. If I understand you correctly, you'd like to bit bang your protocol over a GPIO with timing accurate to < 1/3 us.
This will be a challenge. Tests show that the Beaglebone black GPIO toggle frequency is going to max out at ~2.78MHz writing directly to the SoC IO registers in kernel mode (~0.18 us minimum pulse width).
So, although this might be achievable by the thinnest of margins by writing atomic code in kernel space, I propose another concept:
Implement your custom serial protocol on the SPI bus.
Why?
The SPI bus can be clocked up to 48MHz on the Beaglebone Black, its buffered and can be used with the DMA engine. Therefore, you don't have to worry about disabling interrupts and monopolizing your CPU for this one interface. With a timing resolution of ~0.021us (# 48MHz), you should be able to achieve your timing needs with an acceptable margin of error.
With the bus configured for Single Channel Continuous Transfer Transmit-Only Master mode and 30-bit word length (2 30-bit words for each bit of your protocol):
To write a '0' with your protocol, you'd write the 2 word sequence - 17 '1's followed by 43 '0's - on SPI (#48MHz).
To write a '1' with your protocol, you'd write the 2 word sequence - 43 '1's followed by 17 '0's - on SPI (#48MHz).
From your signal timmings it's easy to figure out that SPI or other serial peripheral can not reach your demand. In your timmings, encoding is based on the width of the pulse. So let's get to the point:
Q1 Could you turn off all interrupts for a duration of 500µs?
A: 0.5ms is quite a long time in embedded system. ISR is born to enable the concurrency of multi-task and improve the real-time capability. Your should keep in mind that ISR and context-switch(in some chip architecture) are all influenced by global interrupt.
But if your top priority is to perform the timmings, and the real-time window of other tasks are acceptable, of cause you can disable the global interrupt in the duration. Even longer. If not, don't do ATOM operation in such a long time.
Q2 How?
A: For a certain chip, there's asm instruction for open/close global interrupt undoubtedly. Find the instructions or the APIs provided by your OS, do the 3 steps below(pseudocode):
state_t tState = get_interrupt_status( );
disable_interrupt( );
... /*your operation here*/
resume_interrupt( tState );
I have read that the postscalar of a timer specifies how many times the counter has to overflow inorder to get an interrupt.
But i have a doubt there.
So what i understand is if i put 0x55 and start timer with postscalar as 2, then timer will count from 0x55 to 0xFF and then again 0x55 to 0xFF and generate an interrupt.
Consider a case that i start the timer in an external inetrrupt. My requyirement may be to get the timegap between two interrupt. I start the timer in first interrupt, then read the timer in the next interrupt.
but if i have put postscalar then i will get the wrong time right.
I just used this as an example to make my question clear.
Edit: So will there be any issue if a timer value is read when postscalar turned ON
Usage Context: To get time difference between two interrupts
No. PostScale - Pre-Scale divide the clock input/output so you can sample at lower frequencies or intervals, depending on the application where you need more count than available. Let's say you have a XTAl of 8MHz with a Pre-Scaler of 1:8 (found on many PICS), you won't sample at 8MHz but at 1MHz.
Addind a pre-scaler - Post-Scaler will change the time between your 2 interrupts, surely. But that won't affect the reading of the counter value, assuming you count a variable each time there's one of the 2 interrupts on. You will simply count slower, or faster, depending on which timer you are using (most of them only have a pre-scaler option).
I am implementing a time counter on my atmega 328p. I looked on the implementation of arduino millis function and I am bit confused, why they use Timer Overflow Interrupt which is executed every 1.024 ms (freg = 16MHz, 64 prescaling), when they could use Output Compare Match Interrupt which can be set up to trigger exactly every 1ms (OCR0A = 249). Is there any advantage to use Timer Overflow Interupt and do some corrections to counted ms over Output Compare Match interupt that is executed exactly every 1ms? Or why they are using it?
The counter value TCNT is used for calculation of microseconds beyond interrupt. Using compare match for defining TOP value would generate exact interrupt but complicates finer micros calculation as TCNT is reset. Using compare match for non TOP value (for PWM generation) does not generate periodic 1ms interrupt.
I'm personally using as second timer for sampling TOP value defined by OCRxA register.
Im using Ethernut 2.1 B and I need a C program that outputs a clock signal at the timer 1 output B, with other words on output OCIB. The frequency of the clock signal should be at 1.0 kHz.
Anyone know how this could be done?
You need to look in COM bits for your timer. For instance, for Timer0 (8-bit), the COM bits are set in the TCCR0 register. Probably the setting you'd be interested in is
TCCR0 |= (0<<COM1)|1<<COM0); // Toggle OC0 on compare match
This will toggle the OC0 (pin14) line when timer reaches the specified value.
Which timer you use depends on the precision you need: obviosely the 16-bit timers can give you more precise time resolution then the 8-bit timers.
The setting of the registers for your specific frequency (1Khz) depends on the clock speed of your chip, and which timer you are using: the timers use a pre-scaled general clock signal (see table 56 of the datasheet for possible values). This means that the prescaler settings will depend on your clock speed, and how high you want to count. For most precision you will want to count as high as possible, which means the lowest possible prescaler setting compatible with your timer's maximum value.
As far as where to start, generally, reading the datasheet is a good place, but googling "AVR timer" can also be very helpful.
It seems to be based on the Atmel ATmega 128, so read that CPU's data sheet to figure out how to program the timer hardware.
Not sure if this microcontroller supports directly driving an output from a timer, if it doesn't you're going to have to do it in software from the interrupt service routine.