Atmega2560 setup PWM and interrupt on positive edge - c++

I am trying to do 2 operations on the same timer: PWM and interrupt on positive edge. I can make both work individually, but can not seem to make them work together. I am using at atmega2560 chip on the Arduino board and trying to do it on Timer1, and this is the code that does the PWM:
TCCR1A = 0;
TCCR1B = 0;
TCCR1A |= (1<<WGM11)|(1<<COM1A1)|(1<<COM1B1);
TCCR1B |= (1<<WGM12)|(1<<WGM13)|(1<<CS10);
ICR1 = 29999;
OCR1A = 0;
OCR1B = 0;
ICR1 sets the frequency to about 533Hz, and the OCR1A is the duty cycle; I vary that throughout the rest of my software, as it is meant to control a DC motor. What I want to do next is on every positive edge of the 533Hz, is to trigger and interrupt. I have tried to use TIMSK1 but could not seem to make it work. Would anyone know how to program this? Thanks

You should provide the individual code for the positive edge detection and pwm since you said you can make them both individually work. It would make it easier to see what you're doing and why they do not work together as opposed giving us nothing to work from. The implementation of PWM and interrupt is dependant on the environment and your ic, but the general algorithms are the same. Its most likely something minor you are overlooking in your code so I would include that to get more responses.

Related

Switching the GPIO of a Raspberry Pi at a fixed frequency

I have a 208 - 232 Bit long binary signal that I want to send via a GPIO of the raspberry pi.
The delay between the bits needs to be constant.
How can I achieve this ?
The simplest solution that came to my mind was this (pseudocode):
send(gpio, message, delay){
for(int i = 0; i < lenght(message); i++){
if (message[i] == 1){
gpio.high()
}
else{
gpio.low()
}
sleep(delay)
}
}
But the frequency at which I want to send this message is around 40kHz so the delay between two bits is only 25us.
How can I assure it is exactly&constantly that much delay.
In userspace there is no way to garantee that anything is happening in "real time".
Because of this I decided using a seperate Microcontroller that is responsible for time critical features that communicates via I2C or UART with the RaspberryPi.
This way the RaspberryPi can do high abstraction level decisions and show animation to a user while being able to send messages over ultrasound.
Another way I came up with is to create a file similar to .wav and then use DMA or other techniques like with audio. But as I haven't tried it I don't know if the Pi is sufficient to do this at higher Samplingrates.

Problem with programming a basic hardware

I have an animation shown on LEDs. When the button is pressed, the animation has to stop and then continue after the button is pressed again.
There is a method that processes working with the button:
void checkButton(){
GPIO_PinState state;
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
if (state == GPIO_PIN_RESET) {
while(1){
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
if (state == GPIO_PIN_SET){
break;
}
}
//while (state == GPIO_PIN_RESET) {
//state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
//}
}
}
GPIO_PIN_SET is the default button position. GPIO_PIN_RESET is the condition when the button is pressed. The commented section is what I tried instead of the while(1){...} loop. The checkButton() method is called in the main loop from time to time to be run. The program runs on STM32 with an extension module (here the type of an extension module does not matter).
The fact is that this method stops animation just for a moment and does not work as I would like it to. Could you correct anything about this program to make it work properly?
Could you correct anything about this program to make it work
properly?
My guess is that you are trying to add a 'human interaction' aspect to your design. Your current approach relies on a single (button position) sample randomly timed by a) your application and b) a human finger. This timing is simply not reliable, but the correction is possibly not too difficult.
Note 1: A 'simple' mechanical button will 'bounce' during it's activation or release (yes, either way). This means that the value which the software 'sees' (in a few microseconds) is unpredictable for several (tbd) milliseconds(?) near the button push or release.
Note 2: Another way to look at this issue, is that your state value exists two places: in the physical button AND in the variable "GPIO_PinState state;". IMHO, a state value can only reside in one location. Two locations is always a mistake.
The solution, then (if you believe) is to decide to keep one state 'record', and eliminate the other. IMHO, I think you want to keep the button, which seems to be your human input. To be clear, you want to eliminate the variable "GPIO_PinState state;"
This line:
state = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15);
samples the switch state one time.
HOWEVER, you already know that this design can not rely on the one read being correct. After all, your user might have just pressed or released the button, and it is simply bouncing at the time of the sample.
Before we get to accumulating samples, you should be aware that the bouncing can last much more than a few microseconds. I've seen some switches bounce up to 10 milliseconds or more. If test equipment is available, I would hook it up and take a look at the characteristics of your button. If not, well, you can try the adjusting the controls of the following sample accumulator.
So, how do we 'accumulate' enough samples to feel confident we can know the state of the switch?
Consider multiple samples, spaced-in-time by short delays (2 controls?). I think you can simply accumulate them. The first count to reach tbr - 5 (or 10 or 100?) samples wins. So spin sample, delay, and increment one of two counters:
stateCount [2] = {0,0}; // state is either set or reset, init both to 0
// vvv-------max samples
for (int i=0; i<100; ++i) // worst case how long does your switch bounce
{
int sample = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_15); // capture 1 sample
stateCount[sample] += 1; // increment based on sample
// if 'enough' samples are the same, kick out early
// v ---- how long does your switch bounce
if (stateCount[sample] > 5) break; // 5 or 10 or 100 ms
// to-be-determined --------vvv --- how long does switch bounce
std::this_thread::sleep_for(1ms); // 1, 3, 5 or 11 ms between samples
// C++ provides, but use what is available for your system
// and balanced with the needs of your app
}
FYI - The above scheme has 3 adjustments to handle different switch-bounce durations ... You have some experimenting to do. I would start with max samples at 20. I have no recommendation for sleep_for ... you provided no other info about your system.
Good luck.
It has been a long time, but I think I remember the push-buttons on a telecom infrastructure equipment bounced 5 to 15 ms.

I have a problem lighting an LED in a microcontroller stm32f373 discovery

I have a problem lighting the LED in the microcontroller device discovery stm32f373
I used STM32 cube mx and the HAL library the program was executed, but the LED did not light up. Performed work according to STM instruction. Lesson 4. HAL library. STM32 CUBE MX. LEDs and button link russian
set pins for power, inputs and outputs
discovery
Turn on the rcc-> HSE bus
In Clock Configuration, enabled HSE. Configured by manipulated as follows
clock
Added an endless loop changing it.
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(5000); //1 minut
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_8);
HAL_Delay(5000);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_8);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_9);
HAL_Delay(5000);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_9);
}
Did I do everything right?
Explain the reason why the LED may not light.
The pins of the microcontroller have their own identifier. Where can I find leg information? Will this fit Discovery Device Description ?
I used the English documentation offered by the author of the lesson, only the version for my controller. Description of STM32F3 HAL and low-layer drivers STM32F373xx
LED pin PC9, PC8
You need a second delay with HAL_Delay. Otherwise you toggle the LED, jump to the begin of the while and toggle the LED again. So it might be that the LED is switched on for only a few clock cycles depending on the initial state of the I/O.
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_8);
HAL_Delay(500);
HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_8);
}
You need to enable the clock for the GPIO peripheral which the LED is connected to, before you set up pins as outputs and try to toggle them.
In the RCC->AHBENR there are bits to turn individual GPIO ports clocks on and off, GPIOD is bit 20, so RCC->AHBENR |= (1 << 20); would do. There will be defines existing depending on which librarys you're using, so use those instead of the (1 << 20) magic number.
EDIT
After your edit, you've added at the bottom that the LEDs are pins PC8 & PC9, your code is toggling PD8 and PD9. Check which way it should be.
Have you configured the GPIO as outputs in STM32CubeMX?
Is interrupts enabled? If not, you will notice when debugging that HAL_Delay never returns. Try to place a couple of breakpoints and see if your while-loop actually executes.

IRQ 8 isn't working... HW or SW?

First, I program for Vintage computer groups. What I write is specifically for MS-DOS and not windows, because that's what people are running. My current program is for later systems and not the 8086 line, so the plan was to use IRQ 8. This allows me to set the interrupt rate in binary values from 2 / second to 8192 / second (2, 4, 8, 16, etc...)
Only, for some reason, on the newer old systems (ok, that sounds weird,) it doesn't seem to be working. In emulation, and the 386 system I have access to, it works just fine, but on the P3 system I have (GA-6BXC MB w/P3 800 CPU,) it just doesn't work.
The code
setting up the interrupt
disable();
oldrtc = getvect(0x70); //Reads the vector for IRQ 8
settvect(0x70,countdown); //Sets the vector for
outportb(0x70,0x8a);
y = inportb(0x71) & 0xf0;
outportb(0x70,0x8a);
outportb(0x71,y | _MRATE_); //Adjustable value, set for 64 interrupts per second
outportb(0x70,0x8b);
y = inportb(0x71);
outportb(0x70,0x8b);
outportb(0x71,y | 0x40);
enable();
at the end of the interrupt
outportb(0x70,0x0c);
inportb(0x71); //Reading the C register resets the interrupt
outportb(0xa0,0x20); //Resets the PIC (turns interrupts back on)
outportb(0x20,0x20); //There are 2 PICs on AT machines and later
When closing program down
disable();
outportb(0x70,0x8b);
y = inportb(0x71);
outportb(0x70,0x8b);
outportb(0x71,y & 0xbf);
setvect(0x70,oldrtc);
enable();
I don't see anything in the code that can be causing the problem. But it just doesn't seem to make sense. While I don't completely trust the information, MSD "does" report IRQ 8 as the RTC Counter and says it is present and working just fine. Is it possible that later systems have moved the vector? Everything I find says that IRQ 8 is vector 0x70, but the interrupt never triggers on my Pentium III system. Is there some way to find if the Vectors have been changed?
It's been a LONG time since I've done any MS-DOS code and I don't think I ever worked with this particular interrupt (I'm pretty sure you can just read the memory location to fetch the time too, and IRQ0 can be used to trigger you at an interval too, so maybe that's better. Anyway, given my rustiness, forgive me for kinda link dumping.
http://wiki.osdev.org/Real_Time_Clock the bottom of that page has someone saying they've had problem on some machines too. RBIL suggests it might be a BIOS thing: http://www.ctyme.com/intr/rb-7797.htm
Without DOS, I'd just capture IRQ0 itself and remap all of them to my own interrupt numbers and change the timing as needed. I've done that somewhat recently! I think that's a bad idea on DOS though, this looks more recommended for that: http://www.ctyme.com/intr/rb-2443.htm
Anyway though, I betcha it has to do with the BIOS thing:
"Notes: Many BIOSes turn off the periodic interrupt in the INT 70h handler unless in an event wait (see INT 15/AH=83h,INT 15/AH=86h).. May be masked by setting bit 0 on I/O port A1h "

Multiple functions simultaneously in Arduino

I'm working on an Arduino sketch where I created two traffic lights, one for normal traffic and one for pedestrians. I created a function for each of these two lights, which loops it through it's cycle (for example: turn yellow, wait 20 seconds, then turn red and wait again). These are called aTrafficlight() and pTrafficlight, where a is the normal light and p the one for the pedestrians. In my loop() function I set a digitalRead for a button. When this button is pressed the traffic lights should cycle through their loops one at a time (so the normal light turns red, pTrafficlight waits a bit, then turns green, blinks a few times, turns red, waits and ends the loop, so it goes to it's original state.)
This all works. But now I want to add a buzzer. This buzzer must beep once a second while the pTrafficlight is red, once a tenth second while it's green and twice per two seconds while it's flashing green.
Here I encountered a few problems:
- When waiting in original state (button's not pressed) it seems I can sometimes press the button without reaction because the loop is still going. I need to figure out how to avoid waiting in the loop when buttonState == LOW. (There's a function wait(int sec))
- When the button is pressed, it loops through the cycles. I could just write some kind of loop implementing the traffic light being red and beeping at the same time, but I'd rather keep these seperated.
- Same for the double beeps. I do not want the beeping and flashing of the light to be in the same for loop, as it's confusing and difficult to read and understand the code.
Here's my loop():
int buttonState = 0;
void loop(){
buttonState = digitalRead(pButton);
if(buttonState == LOW){
vSet("red");
pSet("green");
// This is where I tried to create the sound.
digitalWrite(pSound, HIGH);
delay(10);
digitalWrite(pSound, LOW);
wait(1);
} else {
aTrafficlight();
pTrafficlight();
}
}
Is there a way to solve my problems with multithreading? I tried to look it up at arduino.cc and google, but I can't find a way I understand enough to use it in my existing code.
If not, do you have any better suggestions?
You don't need multi-threading. You need to use timers, whether via interrupts (as Pawel wrote) or via another mechanism, such as the Metro library, that lets the code continue to loop through while the timer is running. See this question and answer: How Can I Create Interrupts in C for Arduino
Coincidentally, I recently posted some material both on state machines and the Arduino, as Hans Passant mentioned, and on alternatives to delay(), both with additional references you might find useful.
You could use a time-slice design. Let me just outline this in very general terms.
First code loop so that it always issues a delay(1) and set a mod 10 counter as:
int stopWhen = -1; // at startup
// etc.
x = (x+1)%10; // every time loop execs
Then when buttonState == LOW
if (stopwWhen = -1)
{
stopWhen = x;
// beep etc.
}
But on every loop:
// always exec this:
if (stopWhen == x)
{
stopWhen = -1;
// stop beeping.
}