I multiple interrupts running:
the tick interrupt on the TIMER_B0_VECTOR
my sample initiation interrupt on the TIMER_B1_VECTOR
and a sample complete interrupt on the ADC12_VECTOR – this stores data in a buffer and sends a buffer pointer to the main sampling task using a FreeRTOS Queue
I have two tasks running:
the main sample processing task, wakes when a data buffer (sent by the ADC interrupt) is received
a second task that writes to external memory, uses a FreeRTOS semaphore for syncronization
I have two MCLK rates:
1MHz sourced from XT1 – connected to an external 32KHz crystal – multiplied using the FLL
20MHz sourced from XT2
I switch to 20MHz every time the main sample processing task begins processing. I switch back to 1MHz in the IDLE task.
I go to low power mode 3 in the IDLE task Any thoughts? What are some easy ways to hung up when lots of interrupts are firing? When using queues within ISRs? When going to low power mode? I’m quite stumped at the moment. Here is my code with the actual application specific code removed:
/// SD Write Task
portTASK_FUNCTION( vSDWriteTask, pvParameters ) {
static UINT8* blocks[BQ_LEN];
/* The parameters are not used. */
( void ) pvParameters;
vPortFree(pvParameters);
for( ;; ) {
// wait to write
xSemaphoreTake(mainSDWriteSemphr, portMAX_DELAY);
GREEN_ON();
// turn on high speed clock
vHal_TurnOnXT2();
UINT8 full_blocks;
// read full blocks from sdfifo
if (xSemaphoreTake(mainDataFifoMutex, 1000) == pdTRUE) {
full_blocks = sbroDataFifo_readFullBlocks(&sdfifo, blocks);
xSemaphoreGive(mainDataFifoMutex);
} else {
xTaskHandle current_task = xTaskGetCurrentTaskHandle();
vApplicationError(GENERIC_ERROR, "SDFifo Inaccessable!n");
}
// write to sd
...
...
TotalBlocksWritten += full_blocks;
// free blocks in sdfifo
if (xSemaphoreTake(mainDataFifoMutex, 1000) == pdTRUE) {
sbroDataFifo_freeBlocks(&sdfifo, full_blocks);
xSemaphoreGive(mainDataFifoMutex);
} else {
xTaskHandle current_task = xTaskGetCurrentTaskHandle();
vApplicationError(GENERIC_ERROR, "SDFifo Inaccessable!n");
}
}
}
/// Sample Processing Task
portTASK_FUNCTION(vSampleProcessingTask, pvParameters)
{
/* The parameters are not used. */
( void ) pvParameters;
vPortFree(pvParameters);
// ------ start sampling mainState machine ------
TB0CCR1 = TB0R + LOSAMPLECOUNTS;
TB0CCTL1 = CCIE;
// ------ setup adc ------
vHal_SetupADC12ForSequentialSampling();
for( ;; ) {
event = E_NO_EVENT;
if(xQueueReceive(EventQueue, &event, 1000) == pdTRUE) {
// turn on high freq clock
vHal_TurnOnXT2();
switch(event) {
case ...:
...
break;
}
// check for sd write
if (xSemaphoreTake(mainDataFifoMutex, 1000) == pdTRUE) {
// check from sd write
if (sdfifo.full_blocks >= BLOCKS_TO_WRITE) {
xSemaphoreGive(mainSDWriteSemphr);
}
xSemaphoreGive(mainDataFifoMutex);
} else {
vApplicationError(GENERIC_ERROR, "data fifo timeout!n");
}
} else {
vApplicationError(GENERIC_ERROR, "event queue timeout!n");
}
}
}
void main() {
// app specific stuff
...
// ------ FreeRTOS specific ------
// create queues
EventQueue = xQueueCreate(10, 1);
// create mutex semaphore for sdfifo
mainDataFifoMutex = xSemaphoreCreateMutex();
// create semaphore for triggering the sd write task
vSemaphoreCreateBinary(mainSDWriteSemphr);
// take semaphore so sd write task blocks immediately (because there isn't any data to write);
xSemaphoreTake(mainSDWriteSemphr, 1);
// create tasks
xTaskCreate( vSampleProcessingTask, ( signed char * ) "SamplePro", configMINIMAL_STACK_SIZE*3, NULL, mainSAMPLE_PROC_PRIORITY, &mainSampProcTask);
xTaskCreate( vSDWriteTask, ( signed char * ) "SDWrite", configMINIMAL_STACK_SIZE*2, NULL, mainSD_WRITE_PRIORITY, &mainSDWriteTask);
/* Start the scheduler. */
vTaskStartScheduler();
}
void vApplicationTickHook( void )
{
const unsigned short usACLK_Frequency_Hz = 32768;
TB0CCR0 += usACLK_Frequency_Hz / configTICK_RATE_HZ;
}
const unsigned short usACLK_Frequency_Hz = 32768;
/* Ensure the timer is stopped. */
TB0CTL = 0;
/* Run the timer from the ACLK. */
TB0CTL = TBSSEL_1;
/* Clear everything to start with. */
TB0CTL |= TBCLR;
/* Set the compare match value according to the tick rate we want. */
TB0CCR0 = usACLK_Frequency_Hz / configTICK_RATE_HZ;
/* Enable the interrupts. */
TB0CCTL0 = CCIE;
/* Start up clean. */
TB0CTL |= TBCLR;
/* Continuous mode. */
TB0CTL |= MC_2;
}
void vApplicationIdleHook( void )
{
/* Called on each iteration of the idle task. In this case the idle task
just enters a low power mode. */
TURN_OFF_XT2();
__bis_SR_register( LPM3_bits + GIE );
__no_operation();
}
/// ADC12 interrupt routine, process data once the A/D has sampled all 8 channels
#pragma vector = ADC12_VECTOR
static __interrupt void ADC12ISR (void)
{
// RED_ON();
// Clear interupts and disable ADC.
ADC12IFG = 0; // clear ADC12 interrupt
ADC12CTL0 = 0; //stop conversion
ADC12CTL0 = 0;
// get data
// ...
portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
if (option_1) {
// save data to buffer
...
...
// send for processing every 100 times
if (finished) {
// some processing
...
event = 0
xQueueSendFromISR(EventQueue, &event, &xHigherPriorityTaskWoken);
if (done) {
// decision
if (decision) {
event = 3;
xQueueSendFromISR(EventQueue, &event, &xHigherPriorityTaskWoken);
}
}
__bic_SR_register_on_exit(LPM3_bits);
}
} else {
// save data to buffer
...
// send for processing every 50 times
if (finished) {
// some processing
...
UINT8 event = 1;
xQueueSendFromISR(EventQueue, &event, &xHigherPriorityTaskWoken);
if (done) {
xQueueSendFromISR(EventQueue, &event, &xHigherPriorityTaskWoken);
if (change rate) {
event = 0;
xQueueSendFromISR(EventQueue, &event, &xHigherPriorityTaskWoken);
}
}
// wake up main from sleep
__bic_SR_register_on_exit(LPM3_bits);
}
}
// THIS MUST BE THE LAST THING DONE IN THE ISR.
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
#pragma vector=TIMER0_B1_VECTOR
static __interrupt void Timer_B1(void)
{
switch(__even_in_range(TB0IV, 16)) {
case 0: break; // No Interrupt
case 2:
// TB0CCR1 - sampling
// initiate sample
...
break;
case 4: // TB0CCR2
break;
case 6:
// TB0CCR3
break;
case 8: // TB0CCR4
break;
case 10: // TB0CCR5
break;
case 12: // TB0CCR6
break;
case 14: // TB0CCR7
break;
case 16: break; // TB0CTL TBIFG, timer overflow
}
}