Pumpkin, Inc.

Pumpkin User Forums

Salvo Context Switching and Timer Issue

If you can't make Salvo do what you want it to do, post it here.

Salvo Context Switching and Timer Issue

Postby ben.phillips » Fri Dec 23, 2016 3:27 pm

Whenever I try to use commands that should context switch for some amount of time, such as OS_Delay() and OS_WaitBinSem(), it appears that my program will context switch and never return.

I was using OS_WaitBinSem(PAYLOAD_BYTE_RX, TIMEOUT); in a function I made for reading from a uart, and I was signaling the semaphore in a UART Rx ISR. I verified that the ISR was being hit, and that it was signaling the semaphore using OSSignalBinSem(PAYLOAD_BYTE_RX), I also checked to make sure that the call to OSSignalBinSem returned OSNOERR. But execution of my read function never resumed, making it seem like the semaphore was never signaled.

If I never signal the semaphore it seems that the call never times out, and execution of my read function never resumes. If I try OS_WaitBinSem(PAYLOAD_BYTE_RX, OSNO_TIMEOUT) and verify that I am hitting the interrupt where the semaphore is signaled, it still doesn't continue execution in my read function. So there appears to be an issue with context switching in general, as well as with salvo calls that should context switch for a period of time (I tried OS_Delay(TIMEOUT) to see if it would ever resume execution and it seems to get to that call and stop).

My salvocfg.h file appears as follows:
Code: Select all
   
#define OSEVENTS   20
#define OSMESSAGE_QUEUES  10
#define OSEVENT_FLAGS 0
#define OSENABLE_EVENT_TRYING      TRUE
#define OSTASKS                                        9
#define OSENABLE_MESSAGES         TRUE
#define OSENABLE_TIMEOUTS                     TRUE
#define OSENABLE_MESSAGE_QUEUES      TRUE
#define OSENABLE_BINARY_SEMAPHORES    TRUE
#define OSBYTES_OF_DELAYS                     4  //32-byte delays
#define OSBYTES_OF_TICKS                       4  //32-byte OStimerTicks
#define OSENABLE_BOUNDS_CHECKING   TRUE


OSInit() is called in my main function at the start of the program.
In my main function I am creating the binary semaphore with OSCreateBinSem(PAYLOAD_BYTE_RX, 0);
Main has an infinite loop that simply contains a call to OSSched();
My read function is running in a salvo task that I set up, and I assume if the task itself wasn't setup properly then it wouldn't have started executing in the first place.
I have a periodically timed interrupt that calls OSTimer().

I believe these are the general setup steps I need, but obviously I'm doing something wrong. I feel I should note, for testing purposes I am not running any other tasks, just the task that is testing my read function. I don't think that would cause any issues, but then again if there are no other tasks to context switch to then maybe that could be an issue, I don't know.
ben.phillips
 
Posts: 8
Joined: Mon Dec 12, 2016 12:23 pm

Re: Salvo Context Switching and Timer Issue

Postby aek » Sat Dec 24, 2016 8:56 am

I would like to see your code (all of it, sounds like it's pretty small) and a screen dump of the project's organization. A couple of possibilities:

1) You are linking to a Salvo library, yet you have a salvocfg.h for a source-code build.

2) Your event handles are off-by-one (rare).

3) Your timer ISR (which is calling OSTimer()) is not, in fact, calling OSTimer(), at least not regularly.

Generally speaking, if none of the time-based services are working, that strongly suggests that OSTimer() is not, in fact, being called regularly. That can happen if the control of interrupts is not correct (e.g., the ISR occurred only once, and thereafter, was not re-enabled), or for other reasons.

I suggest you log the time (use OSGetTicks()) and output that somewhere, to ensure that your application is not constantly rebooting.
-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Salvo Context Switching and Timer Issue

Postby ben.phillips » Thu Dec 29, 2016 11:00 am

I verified that my timing interrupt is being called regularly and that OSTimer is working using OSGetTicks, like you suggested. Interestingly, it calls the interrupt regularly UNTIL I try to do any sort of context switch. On my task I'm trying to create I simply inserted OS_Delay(10) and suddenly my timing interrupt stopped getting triggered.

Since I'm only trying to run that one task I thought maybe there's an issue trying to context switch when there are no other tasks running (possibly ending any meaningful execution of my program), so I created one that just loops forever and prints a message whenever OSGetTicks returns a certain number (just to keep it doing something that will print semi regularly so I know it's still running). I've run into some odd behavior with this setup. If I use OS_Delay(1) in my primary task the program stops calling my timing interrupt and I never seem to hit my busy task. If I use OS_Delay(10) instead it will switch from my primary task to the busy task. If I try to force it to context switch back to my primary task from my busy task using OS_Yield() then the timing interrupt stops firing.

I'm not sure I understand what you mean on 1) about linking a salvo library yet having a salvocfg.h file, would you mind explaining why that would be an issue? It does appear though that in my setup I've included salvo as a library, but also included the source files. I've been having issues with salvo all around, initially I had it included as a library but then my program stopped building at one point and didn't start building again until I just manually included all of salvo's source files. I'll fiddle around with my salvo setup to see if having it just linked as a library vs including all the source code works. If it doesn't I'll be posting the relevant parts of my code later today.

Thanks for your help thus far aek!
ben.phillips
 
Posts: 8
Joined: Mon Dec 12, 2016 12:23 pm

Re: Salvo Context Switching and Timer Issue

Postby aek » Fri Dec 30, 2016 11:19 am

It does appear though that in my setup I've included salvo as a library, but also included the source files


Do not do that. Remove the library from your build, as your salvocfg.h is for a source code build.

I do not know which target you are building for, nor which compiler you are using. Have you run the included sample projects that come with each Salvo distribution?
-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Salvo Context Switching and Timer Issue

Postby ben.phillips » Fri Dec 30, 2016 7:25 pm

Removing the library from my build results in errors that prevent me from building. In a spot where I'm using OS_Yield() it gives the following error: undefined reference to 'OSCtxSw', and another similar error occurs saying undefined reference to 'OSDispatch'. If I include the library these errors go away and it builds. Any hints on how to get a source code build properly going would be awesome. Currently I've simply included all of the salvo c and h files from the Src and Inc folders respectively into my project and setup the salvocfg.h file as shown in a previous post. If relevant to know, I'm including the lib_effs_thin_pic24-lm-coff-n.a libraries in my program as well as the libsalvolmcc30s-t.a library currently. I know you said to take out libsalvo, but does the effs_thin_pic24 library need to be removed as well for a source code build?

Sorry I neglected to mention my setup. I'm using the MPLAB X IDE, the xc16 compiler version 1.24, and a PIC24FJ256GB210 mcu. I haven't been able to run the sample project provided, it's a project file for the old mplab ide which I'm horribly unfamiliar with. When trying to run the sample project using the old mplab ide if I open up the workspace for the tut5 pro example it won't build. I'm not sure if there's more setup required besides simply opening the project workspace or if it's supposed to be that straightforward, but at first it won't build because salvo.h isn't included, and adding salvo.h to the project doesn't seem to help anything.

So after much fiddling I noticed a fun behavior. If I have two small tasks running in main.c using os_yield() and os_delay() seem to work just fine, no issues. If I move a task into a different file (in this case payloadSystem.c) then when it calls os_yield() it appears to halt the program, my timing interrupt even stops firing. If I leave the task's function in main.c, but have it call another function in a different file, and that other function calls os_yield() then the program stops running. If I leave a task's function in main.c, but have that function call another function in a different file that uses os_delay() then it restarts my program. If I put the task's function in another file and call os_delay() from it, then then it'll context switch and run my other task (that still resides in main.c), but when the task in main.c calls os_yield() then the program stops running.

In each case where it 'stops running', the debugger still says that the program is running, but my timing interrupt is no longer firing, and if I pause the program and try to step over line by line the IDE doesn't take me to a highlighted line. In fact it appears that I've been thrown to a random address in memory. The pic that I'm using has an address error trap status bit that gets set when the program 'stops running', so due to either my faulty setup or some other issue it appears calling salvo functions somehow throws me into weird, invalid, addresses.

Before anything else it'd probably best to get a proper setup going. As is I can't seem to get things building without the library included.
ben.phillips
 
Posts: 8
Joined: Mon Dec 12, 2016 12:23 pm

Re: Salvo Context Switching and Timer Issue

Postby aek » Sat Dec 31, 2016 1:42 am

Use this (and only this) as your salvocfg.h
Code: Select all
#define OSUSE_LIBRARY        TRUE
#define OSLIBRARY_TYPE       OSL
#define OSLIBRARY_CONFIG     OST
#define OSEVENTS             2
#define OSEVENT_FLAGS        0
#define OSMESSAGE_QUEUES     0
#define OSTASKS              9

Remove all of the Salvo source files from your project, except salvomem.c.

Link to the libsalvolmcc30s-t.a library.

Make sure that your MPLAB IDE settings for XC16 are for the small memory model (I believe that's the default).

effs-thin is a separate product ... no need to use it in your current testing.

Refer to http://www.pumpkininc.com/content/doc/m ... -mcc30.pdf (which is also installed by the Salvo Windows installer) for more information.
-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Salvo Context Switching and Timer Issue

Postby aek » Sat Dec 31, 2016 1:47 am

And turn of all compiler optimizations, just to be on the safe side.

Salvo works great on PIC24 -- the students at Stanford built a large application with 30+ tasks (MPLAB X IDE + XC16 v1.25), many ISRs, EFFS-THIN running at an SPI clock of 8MHz, etc. ... very, very reliable, predictable and robust. Your problems are likely configuration errors.
-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Salvo Context Switching and Timer Issue

Postby ben.phillips » Mon Jan 02, 2017 2:29 pm

Alrighty, for some reason it will build with the large memory model and not small, but I'm working on a small part of a larger project so there could very well just be other things elsewhere in code making that necessary. I do have to include effs thin pic24 library because someone else on the project needs that. But my current setup is: I've changed the settings to be for large code and large data models, I linked to libsalvolmcc30l-t.a, and I changed salvocfg.h to match what you posted. There seems to be slightly more sanity now to what it's doing, but it's still not behaving properly.

I'm running two tasks, I'll refer to them as the primary and secondary task because the primary has a priority 0, and secondary a priority of 5 (for testing purposes only). The secondary is a infinite loop that increments a count and then calls os_yield(). The primary task is running some code to interact with what is essentially a command prompt on a chip connected to the pic via uart. In my code the 'command prompt' on the other chip is simply referred to as the monitor. For testing purposes I've thrown in a couple of calls to os_delay in the primary task in arbitrary places to make sure that everything is working. The primary task starts executing first and calls os_delay(), since there are no other eligible tasks the secondary task runs, and then the primary task resumes. But when I call os_delay from the primary task again the secondary task will not execute, the scheduler keeps getting called, but the secondary task never resumes execution. The primary task then resumes after the delay expires but does not finish before the whole program restarts spontaneously (gotta love magical restarts).

Here's the important bits of my code, please note that each call to usb_print() simply prints out to putty. The results I get from putty come after the code snippet.
Code: Select all
//*******************************************************
// salvocfg.h
//*******************************************************
#define OSUSE_LIBRARY        TRUE
#define OSLIBRARY_TYPE       OSL
#define OSLIBRARY_CONFIG     OST
#define OSEVENTS             2
#define OSEVENT_FLAGS        0
#define OSMESSAGE_QUEUES     0
#define OSTASKS              9



//*******************************************************
// main.c
//*******************************************************
int main(void)
{
  OSInit();

  //make sure SD card is off
  csk_sd_pwr_off();
  csk_sd_close();
  InitializeTasksAndQueues();

  char * msg = "initialized\r";
  usb_print(msg, 12);

  char* schedMsg = "Scheduling\r";

  for (;;)
  {
    // Get and print the state of the secondary task
    uint8 taskState = OSGetStateTask(P_BUSY_FUNC);
    taskState += 48;
    usb_print((char*)&taskState, 1);
   
    usb_print(schedMsg, 11);
   
    OSSched();
  }
  return 0;
}

void InitializeTasksAndQueues()
{
  initRPP();
  OSCreateTask(payloadTest, P_PAYLOAD_TEST, 0);
  OSCreateTask(busyFunc, P_BUSY_FUNC, 5);

  //Timer 2 setup (system heartbeat that dives the soft clock)
  T2CON = 0; //Clear the timer
  TMR2 = 0; //reset the counter to 0
  PR2 = TIMER2_PERIOD; //   //Set the period FCY * desired period
  IPC1bits.T2IP = 1;
  IFS0bits.T2IF = 0; //clear the interrupt flag
  IEC0bits.T2IE = 1; //Enable the interrupt
  T2CONbits.TON = 1;
}

// Secondary task
void busyFunc()
{
  int i = 0;
  while(true)
  {
    char* busyMsg = "busy";
    usb_print(busyMsg, 4);
   
    int eligible = OSAnyEligibleTasks();
   
    if(eligible) // Never resolves to true
    {
      char* msg = "task available\r";
      usb_print(msg, 15);
      OS_Yield();
    }
    if(i == 20)
    {
      char* carReturn = "\r";
      usb_print(carReturn, strlen(carReturn));
      OS_Yield();
    }
    i++;
  }
}

void __attribute__((__auto_psv__, __interrupt__)) _T2Interrupt(void)
{
  // drive the salvo heartbeat
  OSTimer();

  //Clear the interrupt flag
  IFS0bits.T2IF = 0;
}



//*******************************************************
// payloadSystem.c
//*******************************************************

// Primary task
/**
 * @brief Driver for testing. Simply calls the payload_init function which attempts
 * sending an echo and setting some of the vdip's settings.
 */
void payloadTest(void)
{
  while(true)
  {
    char* msg = "in payload interface\r";
    usb_print(msg, strlen(msg));

    OS_Delay(10); // Arbitrary delay to test salvo functionality
   
    payload_init();
  }
}

/**
 * @brief Initializes the usb monitor
 */
void payload_init()
{
  monitor_init();
}



//*******************************************************
// usbMonitorInterface.c
//*******************************************************
/**
 * @brief Sends an echo to make sure we are properly synched and sets the
 * appropriate initial settings for the usb monitor.
 *
 * @return true if synch and setting initialization is successful, otherwise
 * return false
 */
uint8 monitor_init()
{
  char* msg = "In init function\r";
  usb_print(msg, strlen(msg));
 
  // Initial state of the monitor after restart
  monitorState.isSynced = false;
  monitorState.commandSet = ECS;
  monitorState.numericalMode = BINARY;
  monitorState.isPortSet = false;
 
  char* msg2 = "attempting echo\r";
  usb_print(msg2, strlen(msg2));
 
  if(monitor_echo())
  {
    char* successMsg = "echo success in monitor_init()\r";
    usb_print(successMsg, strlen(successMsg));
    monitorState.isSynced = true;
  }

  else
  {
    char* failureMsg = "echo failure\r";
    usb_print(failureMsg, strlen(failureMsg));
    return false;
  }

  return false;
}

/**
 * @brief Sends an echo to the monitor, and if an echo is received back then it
 * returns true
 *
 * @return true (1) if echo is successful, else false (0)
 */
uint8 monitor_echo()
{
  //debug messages
  char* msg = "In echo cmd\r";
  usb_print(msg, 12);
 
  OS_Delay(100);

  // Create monitor echo cmd
  static char echo[] = {'e', '\r'};
 
  // Write out the cmd, then read from uart1
  serial_write((uint8*)(echo), 2);                    // Write echo to monitor
  monitorBuffDataLen = serial_read(aMonitorBuff, 2);  // Read back from monitor

  // If 'e' was sent back, then the echo was successful
  if(aMonitorBuff[0] == 'e')
  {
    char* success = "echo successful in monitor_echo()\r";
    usb_print(success, strlen(success));
    return true;
  }
  else
  {
    return false;
  }
}


The output I get is as follows:
initialized
5Scheduling
in payload interface
0Scheduling
busybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusy
0Scheduling
In init function
attempting echo
In echo cmd
3Scheduling
2Scheduling
2Scheduling
2Scheduling
2Scheduling
2Scheduling
2Scheduling
2Scheduling
2Scheduling
2Scheduling
2Scheduling
2Scheduling
1Scheduling
1Scheduling
1Scheduling
1Scheduling
1Scheduling
1Scheduling
1Scheduling
1Scheduling
1Scheduling
1Scheduling
1Scheduling
1Scheduling
1Scheduling
1Scheduling
0Scheduling
0Scheduling
0Scheduling
0Scheduling
0Scheduling
0Scheduling
0Scheduling
0Scheduling
0Scheduling
0Scheduling
0Scheduling
0Scheduling
in serial write
successfully cleared buff
successful Tx: e
in serial read: e
leaving read function
echo successful in monitor_echo()
initialized
5Scheduling
in payload interface
0Scheduling
busybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusybusy

As you can see a few lines from the end it prints 'initialized' again, which means the the program completely restarted, but the primary task hasn't finished because it should have printed 'echo success in monitor_init()\r' and it's also in a loop anyway so it should just start over. And in the large chunk where it's repeatedly printing 'Scheduling' it should have resumed the secondary task that would print 'busy' 20 times. And printing the result of OSGetStateTask(P_BUSY_FUNC) which is called just before printing 'Scheduling' just appears to be decrementing for no reason, even though the task should be in the eligible state that whole time (or at the very least it should be stuck in just one state, not changing). If I double the delay at that point it will start the number that OSGetStateTask(P_BUSY_FUNC) returns at 6 and then decrement to 0, instead of starting at 3.

I've been tearing through salvo's documentation thinking maybe I'm just misunderstanding how salvo is supposed to be interacted with, but to my understanding this all should be valid and should be switching between tasks just fine. I don't know why it won't execute the secondary task after the second time my primary task calls os_delay, and I have no earthly clue what could be causing the whole program to restart before the primary task fully finishes.
ben.phillips
 
Posts: 8
Joined: Mon Dec 12, 2016 12:23 pm

Re: Salvo Context Switching and Timer Issue

Postby aek » Mon Jan 02, 2017 3:20 pm

Where did you define OSMCC30_LARGE_CM, as per rm-mcc30.pdf?
-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Re: Salvo Context Switching and Timer Issue

Postby aek » Mon Jan 02, 2017 3:25 pm

You're also failing to follow one of Salvo's basic rules (User Manual page page 237):

Rule #3: Persistent Local Variables Must be Declared as Static
-------
aek
aek
 
Posts: 1888
Joined: Sat Aug 26, 2000 11:00 pm

Next

Return to Coding

Who is online

Users browsing this forum: No registered users and 2 guests

cron