Multithreading: Serial and InterruptIn Interrupts Implementation RTOS

Hi,

I am currently doing a project that involves running 2 interrupts. One interrupt is for the zero-cross detection that always runs while the other is for serial interrupt. I made a separate code for each one of those. I want to merge these two programs such that the zero-cross detection should be running in parallel with the other events. May I ask how I can be able to make it using mbed?

Here is the code for the zero-cross detection (intended for the ac phase control circuitry):

#include "mbed.h"
 
//PwmOut led(LED1); // led 1 indicates T1 value
 
// pin for ZeroCross tail input
// An external 1K pullup required
InterruptIn zerocross(PC_0); //ZC DETECT A5
 
// pin for Triac Gate output
DigitalOut TriacGate(PA_0); //TriacGate A0
 
//use timer interrupts to control the power
Timeout TriactriggerOn;

// power control value 0.0=off and 1.0=full on
const float T1 = 0.450;
 
// AC power line frequency
const float powerlinefrequency=60.000;
 
// this interrupt routine is activated after a time delay set by T1 value
void triggerOn()
{
    TriacGate = 1;
  //  wait_ms(1);
//    TriacGate = 0;
}
 
// this interrupt routine is activated by every AC line zero crossing
// it is needed to synchronize the Triac turnon time delay to the AC line
void zeroCrossingInterrupt()
{
    // turn off Triac at zero crossing
    TriacGate = 0;
    // compute time delay using T1 value and set timer interrupt
    // triggers Triac after a small post zero crossing time delay
    TriactriggerOn.attach(&triggerOn, (1.001f-T1)/(2*powerlinefrequency)); // setup TriactriggerOn to call triggerOn after 
                                                                         //(1.001f-T1)/(2*powerlinefrequency) seconds
}
 
int main()
{
    //set up interrupt routine to detect AC line zero crossings
    zerocross.mode(PullUp);
    wait(.2);
    zerocross.rise(&zeroCrossingInterrupt);

    while(1) {
    }
}

and here is for the serial part:

#include "mbed.h"
#include <iostream>
#include <string>
#include "atoh.h"

PwmOut LSU1(PA_1);
DigitalOut LSU1_Start(PB_0);
DigitalOut myled(LED1);

RawSerial pc(USBTX, USBRX);
volatile char bufferA[100];
uint16_t buffer1;
uint16_t checkStart;
int buf_index = 0;

void Rx_interrupt(void)
{
    while(pc.readable())
    {
        bufferA[buf_index] = pc.getc();
        buf_index++;
    }    
}

int main() {
    pc.baud(9600);
    //char c;
    //char buffer[128];
    pc.printf("program started \r\n");
    //LSU1.period_ms(1/0.55);// set PWM period to 10 ms; frequency to 100 Hz
    LSU1.period((float)1/1000); //set your period as the inverse of frequency
    //LSU1.period(1/1000.0); //set your period as the inverse of frequency
    //LSU1.period(1/frequency); //set your period as the inverse of frequency
    //LSU1.write(0.50f);      // 50% duty cycle, relative to period
    LSU1=0.5;      // set duty cycle to 50%
    LSU1_Start=1; // set LSU1_Start pin to high
    //LSU1_Start.write(0);     // set LSU1_Start pin to low
    pc.attach(&Rx_interrupt);

    while(1) {
        if (buf_index > 2)
        {   
            //pc.printf("%s \n",bufferA); 
            buffer1 = atoh<uint16_t> ((char*)bufferA);
            //pc.printf("%d \n",buffer1);   
            checkStart = buffer1 >> 8;
            pc.printf("%d \n",checkStart);  

            if(checkStart == 1)
            {
                myled = 1;
            }
            if(checkStart == 2)
            {
                myled = 0;
            }
            //pc.printf("%d\n",bufferA[buf_index]);      
            //pc.printf("Size of bufferA is %d \n", sizeof(bufferA));
            //pc.printf("I got '%s'\n", bufferA);
            
            for (int i=0; i<sizeof(bufferA); i++){
                bufferA[i] = 0;
            }
            buf_index = 0;
            
        } 
        
        //pc.printf("Nucleo is still awake! \r\n");
       //pc.printf("%i", sizeof(char));
        
    }
}

Thank you. I believe that it is something to do with RTOS. I hope you can give me a quick start and ideas on how I should be able to combine these programs.

By the way, I am running this on nucleo-f303re board.

@aglass0fmilk

Update:

I think I made it somewhat working. Here is my code:

#include "mbed.h"

#include "atoh.h"

Thread ISRthread(osPriorityAboveNormal);
osThreadId ISRthreadId;
 
RawSerial pc(USBTX, USBRX);
 
DigitalOut myled(LED1);
PwmOut LSU(PA_6); // frequency generator pin D12
DigitalOut LSU1_Start(PA_7); // LSU1 start pin D11

void newInput();
void ISR_thread();

volatile char bufferA[3];
volatile uint16_t buffer1;
volatile uint16_t checkStart;
volatile uint16_t rpmData;
volatile int buf_index = 0;

//zero cross
// pin for ZeroCross tail input
// An external 1K pullup required
InterruptIn zerocross(PC_0); //ZC DETECT A5

// pin for Triac Gate output
DigitalOut TriacGate(PA_0); //TriacGate A0

//use timer interrupts to control the power
Timeout TriactriggerOn;

// power control value 0.0=off and 1.0=full on
const float T1 = 0.450;
 
// AC power line frequency
const float powerlinefrequency=60.000;
 
// this interrupt routine is activated after a time delay set by T1 value
void triggerOn()
{
    TriacGate = 1;
  //  wait_ms(1);
//    TriacGate = 0;
}
 
// this interrupt routine is activated by every AC line zero crossing
// it is needed to synchronize the Triac turnon time delay to the AC line
void zeroCrossingInterrupt()
{
    // turn off Triac at zero crossing
    TriacGate = 0;
    // compute time delay using T1 value and set timer interrupt
    // triggers Triac after a small post zero crossing time delay
    TriactriggerOn.attach(&triggerOn, (1.001f-T1)/(2*powerlinefrequency)); // setup TriactriggerOn to call triggerOn after 
                                                                         //(1.001f-T1)/(2*powerlinefrequency) seconds
}
 
int main() {
    
    ISRthread.start(callback(ISR_thread));
    pc.attach(&newInput);                                      //interrupt to catch input
   
   //set up interrupt routine to detect AC line zero crossings
    zerocross.mode(PullUp);
    wait(.2);
    zerocross.rise(&zeroCrossingInterrupt);
    
    while(1) {
    }
}
 
 
void newInput() {
    pc.attach(NULL);                                           //deatch the ISR to prevent recursive calls
    osSignalSet(ISRthreadId,0x01);
}
 
 
void ISR_thread() {
    ISRthreadId = osThreadGetId();
    LSU.period((float)1/1000); //set your period as the inverse of frequency
    LSU=0.5;      // set duty cycle to 50%
    
    for(;;) {
        osSignalWait(0x01, osWaitForever);
        
        while (pc.readable()) {
            //pc.putc(pc.getc()); //echo input back to terminal
            bufferA[buf_index] = pc.getc();
            buf_index++;
            //pc.printf("%s \n",bufferA);
            
            if (buf_index > 2)
            {   
                //pc.printf("%s \n",bufferA);
                buffer1 = atoh<uint16_t> ((char*)bufferA);
                checkStart = buffer1 >> 8;
                rpmData = buffer1 & 0xFF;
                //pc.printf("%d \n",checkStart);  
                pc.printf("%d \n",rpmData);  
    
                if(checkStart == 1)
                {
                    myled = 1;
                    LSU1_Start=1; // set LSU1_Start pin to high
                }
                if(checkStart == 2)
                {
                    myled = 0;
                    LSU1_Start=0; // set LSU1_Start pin to high
                }
                
                for (int i=0; i<sizeof(bufferA); i++){
                    bufferA[i] = 0;
                }
                buf_index = 0;
                //pc.attach(&newInput);                                     //re-attach the ISR
                
            }
            
            pc.attach(&newInput);                                     //re-attach the ISR
        }
        //myled = 1;
        //osDelay(50);
        //myled = 0;
        
        
    }
}

With this code comes another problem but it is not somehow related to this thread (question). I can create another one if you may but if it is okay, I can just tell you about it here.

My challenge/problem is on the serial data received. I want to receive something that starts with a character, say $. Whenever the serial program encounters that, the program will start to store the next data received until such time that it will encounter again an end character, say #. I believe that in this way I can make sure that I am really getting the right data. How can I revise my program to cater this?

Sounds like you might want something along the lines of erpc.

@aglass0fmilk can provide some insight there as well

what is erpc?