Lets say I want to control 2 outputs:
One should send a PWM modulated signal (50Hz). The other one should send a audio signal (lets say a sinus-signal) (lets say with 2kHz).
One of those two tasks is simple to do: just run in a loop:
send some value to output
delay the execution for some ms and jump to 1. again
But how would you solve this problem of sending 2 signals (lets say with different loop frequency, like in our example - 50Hz- 2kHz)?
I'm not sure what is required to output sinus-signal, but here's my take on a solution. First, what I understand you have:
void loop() {
update_pwm_output();
delay(1000/50); // 50 Hz
}
A possible solution:
int last_update = 0;
void loop() {
int mill = millis();
if (mill-last_update > (1000/50)) {
last_update = mill;
update_pwm_output();
}
}
This solution would allow you to execute other code in between updates to your PWM signal.
There are a couple ways to keep a PWM updated while running other code. A library I've used, SoftwareServo, allows you to call its refresh() method periodically and it'll update, where as the Servo library takes up a timer and uses an interrupt to do its updates.
Related
I'm using ASF4 API hal_timer for a ARM Cortex M4. I'm using the timer driver to timing a data sequence.
Why does no reset function exist? I'm using the timer on a TIMER_TASK_ONE_SHOT mode and want to reset it when ever I need to.
I thought a simple
timer_start(&TIMER_0);
timer_stop(&TIMER_0);
would do the trick but does not seem to work.
Is it necessary to re-initialize the timer for each timing event?
I'm probably missing something obvious. Am I approaching this problem incorrectly reason being why the method timer_reset() doesn't exist?
I have no experience of this API, but looking at the documentation it is apparent that a single timer can have multiple tasks on different periods, so resetting TIMER_0 makes little semantic sense; rather you need to reset the individual timer task attached to the timer - of which there may be more than one.
From the documentation (which is poor and contains errors), and the source code which is more reliable:
timer_task_instance.time_label = TIMER_0.time ;
where the timer_task_instance is the struct timer_task instance you want to reset. This sets the start time to the current time.
Probably best to wrap that in a function:
// Restart current interval, return interval.
uint32_t timer_restart( struct timer_descriptor* desc, struct timer_task* tsk )
{
tsk->time_label = desc->time
return tsk->interval ;
}
Then:
timer_restart( &TIMER_0, &timer_task_instance ) ;
Assuming you're using the (edited) example from the ASF4 Reference Manual:
/* TIMER_0 example */
static struct timer_task TIMER_0_task;
static void TIMER_0_task_cb(const struct timer_task *const timer_task)
{
// task you want to delay using non-existent reset function.
}
void TIMER_0_example(void)
{
TIMER_0_task.interval = 100;
TIMER_0_task.cb = TIMER_0_task_cb;
TIMER_0_task.mode = TIMER_TASK_ONE_SHOT;
timer_add_task(&TIMER_0, &TIMER_0_task);
timer_start(&TIMER_0);
}
Instead of resetting, which isn't supported by the API, you could use:
timer_remove_task(&TIMER_0, &TIMER_0_task);
timer_add_task(&TIMER_0, &TIMER_0_task);
which will effectively restart the delay associated with TIMER_0_task.
Under the hood, timer tasks are maintained as an ordered list, in order of when each task will expire, and using the functions provided by the API maintains the list order.
I'm programming an Atmega324a Microcontroller and I'm trying to implement a timer (in this case Timer1) which supposed to make a second led connected to my board blink.
I also need to know how to identify the pin the led is attached to
I've found the data sheet:
http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega164A_PA-324A_PA-644A_PA-1284_P_Data-Sheet-40002070A.pdf
but the details are too technical for me to understand and I don't know where to start looking and most importantly, get to the result, which is the code itself.
Also, What does the ISR function do?
Down below is the current Init_timer function for Timer 0. Is it possible for me to enable both timers at the same time?
static void init_timer(void)
{
// Configure Timer0 for CTC mode, 64x prescaler for 1 ms interval
TCCR0A = _BV(WGM01);
TCCR0B = _BV(CS01) | _BV(CS00);
OCR0A = 124;
TIMSK0 = _BV(OCIE0A);
}
int main(void){
MCUSR = 0;
wdt_disable();
init_pins(); // Reset all pins to default state
init_timer(); // Initialize 1 msec timer interrupt
configure_as_output(LOAD_ON);
configure_as_output(LED1);
configure_as_output(LED2);
sei();
.
.
.
}
ISR(TIMER0_COMPA_vect)
{
static uint16_t ms_count = 0;
ms_count++; // milliseconds counter
if (ms_count == TMP107_POLL_PERIOD)
{
tmp107_command(); // send command to temperature sensor
toggle(LED1); // blink status led
ms_count = 0;
}
}
First of all: StackOverflow is a site to ask questions around source code, it is not a service delivering solutions. Please take the tour, it will help you to get satisfactory answers.
But nevermind, because you're new:
For example, you can implement a timer for a pulse width generator in these steps:
Learn to read data sheets. Nobody can relieve you of this burden.
Learn how to use output pins.
Write some tests to make sure you understand output pins.
Select a timer to measure the clock cycles. Apparently you did that already.
Learn to use this timer. Some timers can generate PWM (pulse width modulated) signals in hardware. However, the output pin is likely to be in a fixed location and the range of possible periods may not meet your requirements.
Write some tests to make sure you understand timers and interrupts.
If the required pulse period is too long for the timer, you can add an extra variable to scale down, for example.
Implement the rest of it.
Also, What does the ISR function do?
This function is called "magically" by hardware when the conditions for the interrupt are met. In the case shown, tmp107_command() and toggle(LED1) are called only every TMP107_POLL_PERIOD times.
Is it possible for me to enable both timers at the same time?
Sure.
I'm basically trying to get a LED to light up after I push a button. Below is the snippet of the code that's supposed to handle this:
void task_player1(void *pvParameters)
{
while (1)
{
if (xSemaphoreTake(player1_signal, portMAX_DELAY))
{
printf(">>>Semaphore taken\n<<<");
ioport_set_pin_level(L1, HIGH);
xSemaphoreGive(player1_signal);
}
else
{
ioport_set_pin_level(L1, LOW);
}
}
}
void task_ctrl(void *pvParameters)
{
bool button1 = 0;
while (1)
{
button1 = ioport_get_pin_level(B1);
if (button1)
{
xSemaphoreGive(player1_signal);
printf("Semaphore given\n");
}
}
}
The way I'm envisioning this is that task_ctrl gives the semaphore on button press. Task_player1 is blocked until it takes the semaphore after which it should turn on the LED.
The problem is it never seems to take the semaphore. I'm running the printf statements to show me how far the program reaches and it never gets into the part where the LED lights up. But when I run xSemaphoreGive without the button press in task_ctrl the semaphore is taken.
The weird part is that "Semaphore given\n" statement gets printed out on button click which should mean that the semaphore is given as well but never gets taken.
The tasks work on their own, I've even managed to give the semaphore without the button press if-statement like I stated above.
I'm guessing it's something with the button press code, which also works on it's own outside the tasks. So what am I doing wrong? Am I not using the FreeRTOS correctly?
Edit: Including the task creation code
#define TASK_STACK_SIZE (2048/ sizeof(portSTACK_TYPE))
xTaskCreate(task_ctrl, (const signed char * const) "Control", TASK_STACK_SIZE, NULL, 1, NULL);
xTaskCreate(task_player1, (const signed char * const) "Player1", TASK_STACK_SIZE, NULL, 1, NULL);
Edit 2: Probably something I should have mentioned is that I'm using FreeRTOS 7.3 since Atmel Studio doesn't have any newer versions. So no yield functions are available, as far as I can tell.
task_ctrl never blocks - which will prevent any task of equal or lower priority from ever running. So if task_player is equal or lower priority the the task will never be scheduled even when the semaphore is given.
It appearing to work without the button polling is harder to explain, but you have not shown that code so I cannot comment.
You should do two things:
Ensure that task_ctrl has lower priority that at least task_player1 (and lower than any task if it does not block - the idle task will never run in this case).
Ensure that task_ctrl blocks - even if that is just a polling delay, so that it does not eat up all available CPU cycles.
while (1)
{
button1 = ioport_get_pin_level(B1);
if (button1)
{
xSemaphoreGive(player1_signal);
printf("Semaphore given\n");
vtaskDelay( 1 ) ; // at least 1 tick
}
}
One possible problem with task_ctrl is that it will give the semaphore continuously and repeatedly while the button is held. Some sort of state change detection and switch de-bounce rather then level polling might be preferable.
An alternative solution to a polling task is to use a hardware interrupt for teh button and have either the polling task block on an event from the ISR, or have the ISR give the semaphore directly - in either case you will have to deal with debounce.
I'm trying to acquire data from an MCU, save them to a file and plot them. The code functions properly for some time, then just hangs randomly (sometimes after 1 sec, sometimes after 1 minute ...!). Also the serialport timeouts are not respected, i.e. I'm not receiving any timeout exceptions. I'm using an FTDI232RL chip. The only time I get a timeout exception is when I unplug it while the program is running.
Code:
private: System::Void START_Click(System::Object^ sender, System::EventArgs^ e) {
seconds=0;
minutes=0;
hours=0;
days=0;
t=0;
if((this->comboBox4->Text == String::Empty)||(this->textBox2->Text == String::Empty)||(this->textBox3->Text == String::Empty)){
this->textBox1->Text="please select port, save file directory and logging interval";
timer1->Enabled=false;
}
else{ // start assigning
w=Convert::ToDouble(this->textBox3->Text);
double q=fmod(w*1000,10);
if(q!=0){
MessageBox::Show("The logging interval must be a multiple of 0.01s");
}
else{
period=static_cast<int>(w*1000);
this->interval->Interval = period;
try{ // first make sure port isn't busy/open
if(!this->serialPort1->IsOpen){
// select the port whose name is in comboBox4 (select port)
this->serialPort1->PortName=this->comboBox4->Text;
//open the port
this->serialPort1->Open();
this->serialPort1->ReadTimeout = period+1;
this->serialPort1->WriteTimeout = period+1;
String^ name_ = this->serialPort1->PortName;
START=gcnew String("S");
this->textBox1->Text="Logging started";
timer1->Enabled=true;
interval->Enabled=true;
myStream=new ofstream(directory,ios::out);
*myStream<<"time(ms);ADC1;ADC2;ADC3;ADC4;ADC5;ADC6;ADC7;ADC8;";
*myStream<<endl;
chart1->Series["ADC1"]->Points->Clear();
chart1->Series["ADC2"]->Points->Clear();
chart1->Series["ADC3"]->Points->Clear();
chart1->Series["ADC4"]->Points->Clear();
chart1->Series["ADC5"]->Points->Clear();
chart1->Series["ADC6"]->Points->Clear();
chart1->Series["ADC7"]->Points->Clear();
chart1->Series["ADC8"]->Points->Clear();
backgroundWorker1->RunWorkerAsync();
}
else
{
this->textBox1->Text="Warning: port is busy or isn't open";
timer1->Enabled=false;
interval->Enabled=false;
}
}
catch(UnauthorizedAccessException^)
{
this->textBox1->Text="Unauthorized access";
timer1->Enabled=false;
interval->Enabled=false;
}
}
}
}
private: System::Void backgroundWorker1_DoWork(System::Object^ sender, System::ComponentModel::DoWorkEventArgs^ e) {
while(!backgroundWorker1->CancellationPending){
if(backgroundWorker1->CancellationPending){
e->Cancel=true;
return;
}
t+=period;
if(t<10*period){
this->chart1->ChartAreas["ChartArea1"]->AxisX->Minimum=0;
this->chart1->ChartAreas["ChartArea1"]->AxisX->Maximum=t+10*period;
}
else {
this->chart1->ChartAreas["ChartArea1"]->AxisX->Minimum=t-10*period;
this->chart1->ChartAreas["ChartArea1"]->AxisX->Maximum=t+10*period;
}
*myStream<<t<<";";
for (int n=0;n<8;n++){
adc_array[n]= this->serialPort1->ReadByte();
}
Array::Copy(adc_array,ADC,8);
for(int f=0; f<8; f++){
*myStream<<ADC[f]<<";";
}
*myStream<<endl;
backgroundWorker1->ReportProgress(t);
}
}
private: System::Void backgroundWorker1_ProgressChanged(System::Object^ sender, System::ComponentModel::ProgressChangedEventArgs^ e) {
chart1->Series["ADC1"]->Points->AddXY(t,ADC[0]);
chart1->Series["ADC2"]->Points->AddXY(t,ADC[1]);
chart1->Series["ADC3"]->Points->AddXY(t,ADC[2]);
chart1->Series["ADC4"]->Points->AddXY(t,ADC[3]);
chart1->Series["ADC5"]->Points->AddXY(t,ADC[4]);
chart1->Series["ADC6"]->Points->AddXY(t,ADC[5]);
chart1->Series["ADC7"]->Points->AddXY(t,ADC[6]);
chart1->Series["ADC8"]->Points->AddXY(t,ADC[7]);
}
the user is allowed to define intervals in seconds for data acquisition (in the code this interval is w after conversion to double). In this case, the program sends a pulse to the MCU requesting a new data transmission. So far, I have been testing this for 1 second intervals (note, during each interval the MCU sends 8 frames, each representing an ADC). However, I need to get this to run for 10ms intervals at some point. Will this be possible? Any idea on how to solve the few problems I mentioned at the beginning?
Thanks in advance
UPDATE
Just to give you an idea of what's happening:
I commented the charting part and ran the program for about 5 minutes, with a reading interval of 1s. So I expected to get around 5x60=300 values in the output file, but I only got 39 (i.e. starting from 1s till 39s). The program was still running, but the data were not getting stored anymore.
Testing was done in release mode and not debug mode. In debug mode, setting a break point under serialport->readbyte(), does not reproduce the problem. My guess is it's a timing issue between program and MCU.
You are making several standard mistakes. First off, do NOT unplug the cable when the port is opened. Many USB emulators don't know how to deal with that, the FTDI driver is particularly notorious about that. They just make the port disappear while it is in use, this invariably gives code that uses the port a severe heart attack. An uncatchable exception is common.
Secondly, you are accessing properties of a class that is not thread-safe in a worker thread. The Chart control was made to be used only in a UI thread, accessing the ChartAreas property in a worker is going to buy you a lot of misery. Getting an InvalidOperationException is pretty typical when you violate threading requirements, it is however not consistently implemented. Nastiness includes random AccessViolationExceptions, corrupted data and deadlock.
Third, you are setting completely unrealistic goals. Pursuing an update every 10 milliseconds is pointless, the human eye cannot perceive that. Anything past 50 milliseconds just turns into a blur. Something that is taken advantage of when you watch a movie in the cinema, it displays at 24 frames per second. The failure mode for that is unpleasant as well, you'll eventually reach a point where you are pummeling the UI thread (or the Chart control) with more updates than it can process. The side effect is that the UI stops painting itself, it is too busy trying to keep up with the deluge of invoke requests. And the amount of memory your program consumes keeps building, the update queue grows without bounds. That does eventually end with an OOM exception, it takes a while to consume 2 jiggabytes however. You will need to prevent this from happening, you need to throttle the rate at which you invoke. A simple thread-safe counter can take care of that.
Forth, you are accessing the data you gather in more than one thread without taking care of thread-safety. The ADC array content is being changed by the worker while the UI thread is reading it. Various amounts of misery from that, bad data at a minimum. A simply workaround is to pass a copy of the data to the ReportProgress method. In general, address these kind of threading problems by using pull instead of push. Get rid of the fire-hose problem by having the UI thread pace the requests instead of trying to have the UI thread keep up.
Here i have one function which is listen mode. this function listing something which i got form some device.
Here when my function is in listen mode that time i want to create timeout. if i will not get any response from particular device than i want o exit from this function and have to notify.
if during this timeout period if i will get response from device than i have to continue with work and stop this timeout and there is no limits to complete this work in any time duration.
So how can i implement this thing for a function.
Any body please can me help me to implement this thing with timeout functionality.
Depending on how you are waiting for a response from this device, the answer to your question will be different. The basic framework is:
int do_something_with_device()
{
if (!wait_for_response_from_device()) {
return TIMEOUT_ERROR;
}
// continue with processing
}
As for how you implement wait_for_response_from_device(), well, every device is different. If you're using sockets or pipes, use select(). If you're interfacing with something that requires a busy-wait loop, it might look like:
int wait_for_response_from_device()
{
time_t start = time(NULL);
while (time(NULL) - start < TIMEOUT) {
if (check_device_ready()) {
return 1;
}
}
return 0;
}
Naturally, the implementation of check_device_ready() would be up to you.
Take a look at man 2 alarm. You can set or disable signals which will be sent to your application after a certain time period elapses.