From 26069275a5493c1eaa4f271b6b050f9d7e36985b Mon Sep 17 00:00:00 2001 From: Peter Wittich Date: Fri, 23 Aug 2019 13:24:46 -0400 Subject: [PATCH 1/4] clean up and centralize interrupt handler functions --- projects/project2/ADCMonitorTask.c | 59 +----- projects/project2/InterruptHandlers.c | 270 ++++++++++++++++++++++++++ projects/project2/InterruptHandlers.h | 61 ++++++ projects/project2/Makefile | 1 + projects/project2/MonitorTask.c | 6 +- projects/project2/project2.c | 170 +--------------- projects/project2/startup_gcc.c | 13 +- 7 files changed, 340 insertions(+), 240 deletions(-) create mode 100644 projects/project2/InterruptHandlers.c create mode 100644 projects/project2/InterruptHandlers.h diff --git a/projects/project2/ADCMonitorTask.c b/projects/project2/ADCMonitorTask.c index f83c5a8c..188ecb26 100644 --- a/projects/project2/ADCMonitorTask.c +++ b/projects/project2/ADCMonitorTask.c @@ -32,10 +32,8 @@ #include "driverlib/rom.h" #include "driverlib/adc.h" -// FreeRTOS -#include "FreeRTOS.h" -#include "FreeRTOSConfig.h" -#include "task.h" +#include "InterruptHandlers.h" + // On Apollo the ADC range is from 0 - 2.5V. // Some signals must be scaled to fit in this range. @@ -108,59 +106,6 @@ float getADCvalue(const int i) -// Stores the handle of the task that will be notified when the -// ADC conversion is complete. -static TaskHandle_t TaskNotifyADC = NULL; - -void ADCSeq0Interrupt() -{ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - ROM_ADCIntClear(ADC1_BASE, 0); - - /* At this point xTaskToNotify should not be NULL as a transmission was - in progress. */ - configASSERT( TaskNotifyADC != NULL ); - - /* Notify the task that the transmission is complete. */ - vTaskNotifyGiveFromISR( TaskNotifyADC, &xHigherPriorityTaskWoken ); - - /* There are no transmissions in progress, so no tasks to notify. */ - TaskNotifyADC = NULL; - - /* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch - should be performed to ensure the interrupt returns directly to the highest - priority task. The macro used for this purpose is dependent on the port in - use and may be called portEND_SWITCHING_ISR(). */ - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); - return; -} - - -void ADCSeq1Interrupt() -{ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - ROM_ADCIntClear(ADC0_BASE, 1); - - /* At this point xTaskToNotify should not be NULL as a transmission was - in progress. */ - configASSERT( TaskNotifyADC != NULL ); - - /* Notify the task that the transmission is complete. */ - vTaskNotifyGiveFromISR( TaskNotifyADC, &xHigherPriorityTaskWoken ); - - /* There are no transmissions in progress, so no tasks to notify. */ - TaskNotifyADC = NULL; - - /* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch - should be performed to ensure the interrupt returns directly to the highest - priority task. The macro used for this purpose is dependent on the port in - use and may be called portEND_SWITCHING_ISR(). */ - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); - return; -} - // there is a lot of copy-paste in the following functions, // but it makes it very clear what's going on here. static diff --git a/projects/project2/InterruptHandlers.c b/projects/project2/InterruptHandlers.c new file mode 100644 index 00000000..e519d590 --- /dev/null +++ b/projects/project2/InterruptHandlers.c @@ -0,0 +1,270 @@ +/* + * InterruptHandlers.c + * + * Created on: Aug 23, 2019 + * Author: wittich + */ + +// includes for types +#include +#include +#include + +#include + +#include "InterruptHandlers.h" + +// local includes +#include "common/uart.h" +#include "common/utils.h" +#include "common/power_ctl.h" +#include "common/i2c_reg.h" +#include "common/pinout.h" +#include "common/pinsel.h" +#include "common/smbus.h" +#include "common/smbus.h" + +// TI Includes +#include "inc/hw_types.h" +#include "inc/hw_memmap.h" +#include "inc/hw_ints.h" +#include "driverlib/pin_map.h" +#include "driverlib/sysctl.h" +#include "driverlib/gpio.h" +#include "driverlib/rom.h" +#include "driverlib/adc.h" +#include "driverlib/rom_map.h" +#include "driverlib/uart.h" +#include "driverlib/interrupt.h" + + + +#include "task.h" +#include "queue.h" +#include "semphr.h" +#include "portmacro.h" + + + +// Stream buffers for UART communication +StreamBufferHandle_t xUART4StreamBuffer, xUART1StreamBuffer; + +void UART1IntHandler( void ) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // + // Get the interrupt status. + // + uint32_t ui32Status = ROM_UARTIntStatus(UART1_BASE, true); + + // + // Clear the asserted interrupts. + // + ROM_UARTIntClear(UART1_BASE, ui32Status); + + // + // Loop while there are characters in the receive FIFO. + // + uint8_t bytes[8]; + int received = 0; + while(ROM_UARTCharsAvail(UART1_BASE)) { + + bytes[received] = (uint8_t)ROM_UARTCharGetNonBlocking(UART1_BASE); + // Put byte in queue (ISR safe function) -- should probably send more than one byte at a time? + if ( ++received == 8 ) { + xStreamBufferSendFromISR(xUART1StreamBuffer, &bytes, 8, &xHigherPriorityTaskWoken); + received = 0; + } + } + if ( received ) + xStreamBufferSendFromISR(xUART1StreamBuffer, &bytes, received, &xHigherPriorityTaskWoken); + + /* If xHigherPriorityTaskWoken was set to pdTRUE inside + xStreamBufferReceiveFromISR() then a task that has a priority above the + priority of the currently executing task was unblocked and a context + switch should be performed to ensure the ISR returns to the unblocked + task. In most FreeRTOS ports this is done by simply passing + xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the + variables value, and perform the context switch if necessary. Check the + documentation for the port in use for port specific instructions. */ + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} + +void UART4IntHandler( void ) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + // + // Get the interrupt status. + // + uint32_t ui32Status = ROM_UARTIntStatus(UART4_BASE, true); + + // + // Clear the asserted interrupts. + // + ROM_UARTIntClear(UART4_BASE, ui32Status); + + // + // Loop while there are characters in the receive FIFO. + // + uint8_t bytes[8]; + int received = 0; + while(ROM_UARTCharsAvail(UART4_BASE)) { + + bytes[received] = (uint8_t)ROM_UARTCharGetNonBlocking(UART4_BASE); + // Put byte in queue (ISR safe function) -- should probably send more than one byte at a time? + if ( ++received == 8 ) { + xStreamBufferSendFromISR(xUART4StreamBuffer, &bytes, 8, &xHigherPriorityTaskWoken); + received = 0; + } + } + if ( received ) + xStreamBufferSendFromISR(xUART4StreamBuffer, &bytes, received, &xHigherPriorityTaskWoken); + + /* If xHigherPriorityTaskWoken was set to pdTRUE inside + xStreamBufferReceiveFromISR() then a task that has a priority above the + priority of the currently executing task was unblocked and a context + switch should be performed to ensure the ISR returns to the unblocked + task. In most FreeRTOS ports this is done by simply passing + xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the + variables value, and perform the context switch if necessary. Check the + documentation for the port in use for port specific instructions. */ + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} + + +tSMBus g_sMaster1; // for I2C #1 +tSMBus g_sMaster2; // for I2C #2 +tSMBus g_sMaster3; // for I2C #3 +tSMBus g_sMaster4; // for I2C #4 +tSMBus g_sMaster6; // for I2C #6 + +volatile tSMBusStatus eStatus1 = SMBUS_OK; +volatile tSMBusStatus eStatus2 = SMBUS_OK; +volatile tSMBusStatus eStatus3 = SMBUS_OK; +volatile tSMBusStatus eStatus4 = SMBUS_OK; +volatile tSMBusStatus eStatus6 = SMBUS_OK; + + + +// SMBUs specific handler for I2C +void +SMBusMasterIntHandler1(void) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + // + // Process the interrupt. + // + eStatus1 = SMBusMasterIntProcess(&g_sMaster1); + // handle errors in the returning function + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} + +void +SMBusMasterIntHandler2(void) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + // + // Process the interrupt. + // + eStatus2 = SMBusMasterIntProcess(&g_sMaster2); + // handle errors in the returning function + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} + +void +SMBusMasterIntHandler3(void) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + // + // Process the interrupt. + // + eStatus3 = SMBusMasterIntProcess(&g_sMaster3); + // handle errors in the returning function + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} + +void +SMBusMasterIntHandler4(void) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + // + // Process the interrupt. + // + eStatus4 = SMBusMasterIntProcess(&g_sMaster4); + // handle errors in the returning function + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} + +void +SMBusMasterIntHandler6(void) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + // + // Process the interrupt. + // + eStatus6 = SMBusMasterIntProcess(&g_sMaster6); + // handle errors in the returning function + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); +} + + + +// Stores the handle of the task that will be notified when the +// ADC conversion is complete. +TaskHandle_t TaskNotifyADC = NULL; + +void ADCSeq0Interrupt() +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + ROM_ADCIntClear(ADC1_BASE, 0); + + /* At this point xTaskToNotify should not be NULL as a transmission was + in progress. */ + configASSERT( TaskNotifyADC != NULL ); + + /* Notify the task that the transmission is complete. */ + vTaskNotifyGiveFromISR( TaskNotifyADC, &xHigherPriorityTaskWoken ); + + /* There are no transmissions in progress, so no tasks to notify. */ + TaskNotifyADC = NULL; + + /* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch + should be performed to ensure the interrupt returns directly to the highest + priority task. The macro used for this purpose is dependent on the port in + use and may be called portEND_SWITCHING_ISR(). */ + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + return; +} + + +void ADCSeq1Interrupt() +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + + ROM_ADCIntClear(ADC0_BASE, 1); + + /* At this point xTaskToNotify should not be NULL as a transmission was + in progress. */ + configASSERT( TaskNotifyADC != NULL ); + + /* Notify the task that the transmission is complete. */ + vTaskNotifyGiveFromISR( TaskNotifyADC, &xHigherPriorityTaskWoken ); + + /* There are no transmissions in progress, so no tasks to notify. */ + TaskNotifyADC = NULL; + + /* If xHigherPriorityTaskWoken is now set to pdTRUE then a context switch + should be performed to ensure the interrupt returns directly to the highest + priority task. The macro used for this purpose is dependent on the port in + use and may be called portEND_SWITCHING_ISR(). */ + portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); + return; +} + + diff --git a/projects/project2/InterruptHandlers.h b/projects/project2/InterruptHandlers.h new file mode 100644 index 00000000..9cebd77d --- /dev/null +++ b/projects/project2/InterruptHandlers.h @@ -0,0 +1,61 @@ +/* + * InterruptHanders.h + * + * Created on: Aug 23, 2019 + * Author: wittich + * + */ + +#ifndef PROJECTS_PROJECT2_INTERRUPTHANDLERS_H_ +#define PROJECTS_PROJECT2_INTERRUPTHANDLERS_H_ + +// local include +#include "common/smbus.h" + + +// FreeRTOS includes +#include "FreeRTOS.h" +#include "FreeRTOSConfig.h" +#include "stream_buffer.h" +#include "task.h" + + +extern StreamBufferHandle_t xUART4StreamBuffer, xUART1StreamBuffer; + +// UART +void UART1IntHandler( void ); +void UART4IntHandler( void ); + +// SMBUs specific handler for I2C +extern tSMBus g_sMaster1; // for I2C #1 +extern tSMBus g_sMaster2; // for I2C #2 +extern tSMBus g_sMaster3; // for I2C #3 +extern tSMBus g_sMaster4; // for I2C #4 +extern tSMBus g_sMaster6; // for I2C #6 + +extern volatile tSMBusStatus eStatus1; +extern volatile tSMBusStatus eStatus2; +extern volatile tSMBusStatus eStatus3; +extern volatile tSMBusStatus eStatus4; +extern volatile tSMBusStatus eStatus6; + +void SMBusMasterIntHandler1(void); +void SMBusMasterIntHandler2(void); +void SMBusMasterIntHandler3(void); +void SMBusMasterIntHandler4(void); +void SMBusMasterIntHandler6(void); + +// ADC interrupts +extern TaskHandle_t TaskNotifyADC; + +void ADCSeq0Interrupt(); +void ADCSeq1Interrupt(); + +// these are from the FreeRTOS code base. +void xPortPendSVHandler(void); +void vPortSVCHandler(void); +void xPortSysTickHandler(void); + + + +#endif /* PROJECTS_PROJECT2_INTERRUPTHANDLERS_H_ */ diff --git a/projects/project2/Makefile b/projects/project2/Makefile index 5f39e8e8..bc316137 100644 --- a/projects/project2/Makefile +++ b/projects/project2/Makefile @@ -91,6 +91,7 @@ ${COMPILER}/project2.axf: ${COMPILER}/ADCMonitorTask.o ${COMPILER}/project2.axf: ${COMPILER}/MonitorTask.o ${COMPILER}/project2.axf: ${COMPILER}/FireFlyTask.o ${COMPILER}/project2.axf: ${COMPILER}/LedTask.o +${COMPILER}/project2.axf: ${COMPILER}/InterruptHandlers.o ${COMPILER}/project2.axf: ${COMPILER}/startup_${COMPILER}.o ## FreeRTOS ${COMPILER}/project2.axf: ${COMPILER}/tasks.o diff --git a/projects/project2/MonitorTask.c b/projects/project2/MonitorTask.c index 7323e327..99fc43dc 100644 --- a/projects/project2/MonitorTask.c +++ b/projects/project2/MonitorTask.c @@ -55,11 +55,7 @@ struct pm_list pm_command_dcdc[] = { extern tSMBus g_sMaster1; -volatile tSMBusStatus eStatus1 = SMBUS_OK; -volatile tSMBusStatus eStatus2 = SMBUS_OK; -volatile tSMBusStatus eStatus3 = SMBUS_OK; -volatile tSMBusStatus eStatus4 = SMBUS_OK; // TODO: move these to the right place -volatile tSMBusStatus eStatus6 = SMBUS_OK; +extern tSMBusStatus eStatus1; float pm_values[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; static float pm_values_max[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; diff --git a/projects/project2/project2.c b/projects/project2/project2.c index 40862998..fcb808d7 100644 --- a/projects/project2/project2.c +++ b/projects/project2/project2.c @@ -25,6 +25,7 @@ #include "common/pinsel.h" #include "common/smbus.h" #include "CommandLineTask.h" +#include "InterruptHandlers.h" // TI Includes #include "inc/hw_types.h" @@ -92,171 +93,6 @@ void Print(const char* str) return; } -// Alternate UART signal handler -/* A stream buffer that has already been created. */ -StreamBufferHandle_t xUART4StreamBuffer, xUART1StreamBuffer; - -void UART1IntHandler( void ) -{ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - // - // Get the interrupt status. - // - uint32_t ui32Status = ROM_UARTIntStatus(UART1_BASE, true); - - // - // Clear the asserted interrupts. - // - ROM_UARTIntClear(UART1_BASE, ui32Status); - - // - // Loop while there are characters in the receive FIFO. - // - uint8_t bytes[8]; - int received = 0; - while(ROM_UARTCharsAvail(UART1_BASE)) { - - bytes[received] = (uint8_t)ROM_UARTCharGetNonBlocking(UART1_BASE); - // Put byte in queue (ISR safe function) -- should probably send more than one byte at a time? - if ( ++received == 8 ) { - xStreamBufferSendFromISR(xUART1StreamBuffer, &bytes, 8, &xHigherPriorityTaskWoken); - received = 0; - } - } - if ( received ) - xStreamBufferSendFromISR(xUART1StreamBuffer, &bytes, received, &xHigherPriorityTaskWoken); - - /* If xHigherPriorityTaskWoken was set to pdTRUE inside - xStreamBufferReceiveFromISR() then a task that has a priority above the - priority of the currently executing task was unblocked and a context - switch should be performed to ensure the ISR returns to the unblocked - task. In most FreeRTOS ports this is done by simply passing - xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the - variables value, and perform the context switch if necessary. Check the - documentation for the port in use for port specific instructions. */ - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); -} - -void UART4IntHandler( void ) -{ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - // - // Get the interrupt status. - // - uint32_t ui32Status = ROM_UARTIntStatus(UART4_BASE, true); - - // - // Clear the asserted interrupts. - // - ROM_UARTIntClear(UART4_BASE, ui32Status); - - // - // Loop while there are characters in the receive FIFO. - // - uint8_t bytes[8]; - int received = 0; - while(ROM_UARTCharsAvail(UART4_BASE)) { - - bytes[received] = (uint8_t)ROM_UARTCharGetNonBlocking(UART4_BASE); - // Put byte in queue (ISR safe function) -- should probably send more than one byte at a time? - if ( ++received == 8 ) { - xStreamBufferSendFromISR(xUART4StreamBuffer, &bytes, 8, &xHigherPriorityTaskWoken); - received = 0; - } - } - if ( received ) - xStreamBufferSendFromISR(xUART4StreamBuffer, &bytes, received, &xHigherPriorityTaskWoken); - - /* If xHigherPriorityTaskWoken was set to pdTRUE inside - xStreamBufferReceiveFromISR() then a task that has a priority above the - priority of the currently executing task was unblocked and a context - switch should be performed to ensure the ISR returns to the unblocked - task. In most FreeRTOS ports this is done by simply passing - xHigherPriorityTaskWoken into taskYIELD_FROM_ISR(), which will test the - variables value, and perform the context switch if necessary. Check the - documentation for the port in use for port specific instructions. */ - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); -} - - -#include "common/smbus.h" -tSMBus g_sMaster1; // for I2C #1 -tSMBus g_sMaster2; // for I2C #2 -tSMBus g_sMaster3; // for I2C #3 -tSMBus g_sMaster4; // for I2C #4 -tSMBus g_sMaster6; // for I2C #6 -extern tSMBusStatus eStatus1; -extern tSMBusStatus eStatus2; -extern tSMBusStatus eStatus3; -extern tSMBusStatus eStatus4; -extern tSMBusStatus eStatus6; -// SMBUs specific handler for I2C -void -SMBusMasterIntHandler1(void) -{ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - // - // Process the interrupt. - // - eStatus1 = SMBusMasterIntProcess(&g_sMaster1); - // handle errors in the returning function - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); -} - -void -SMBusMasterIntHandler2(void) -{ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - // - // Process the interrupt. - // - eStatus2 = SMBusMasterIntProcess(&g_sMaster2); - // handle errors in the returning function - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); -} - -void -SMBusMasterIntHandler3(void) -{ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - // - // Process the interrupt. - // - eStatus3 = SMBusMasterIntProcess(&g_sMaster3); - // handle errors in the returning function - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); -} - -void -SMBusMasterIntHandler4(void) -{ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - // - // Process the interrupt. - // - eStatus4 = SMBusMasterIntProcess(&g_sMaster4); - // handle errors in the returning function - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); -} - -void -SMBusMasterIntHandler6(void) -{ - BaseType_t xHigherPriorityTaskWoken = pdFALSE; - - // - // Process the interrupt. - // - eStatus6 = SMBusMasterIntProcess(&g_sMaster6); - // handle errors in the returning function - portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); -} - - @@ -425,6 +261,8 @@ void vGetTaskHandle( char *key, TaskHandle_t *t) CommandLineArgs_t cli_uart1; CommandLineArgs_t cli_uart4; + + // int main( void ) { @@ -478,7 +316,7 @@ int main( void ) Print("\n\r----------------------------\n\r"); Print("Staring Project2 " FIRMWARE_VERSION " (FreeRTOS scheduler about to start)\n\r"); - Print("Built at " __TIME__"," __DATE__ "\n\r"); + Print("Built at " __TIME__", " __DATE__ "\n\r"); Print( "----------------------------\n\r"); // start the scheduler -- this function should not return vTaskStartScheduler(); diff --git a/projects/project2/startup_gcc.c b/projects/project2/startup_gcc.c index d4c89ae5..8c4fa5aa 100644 --- a/projects/project2/startup_gcc.c +++ b/projects/project2/startup_gcc.c @@ -26,6 +26,7 @@ #include "inc/hw_nvic.h" #include "inc/hw_types.h" #include "driverlib/rom.h" +#include "InterruptHandlers.h" #include "FreeRTOSConfig.h" //***************************************************************************** // @@ -35,18 +36,6 @@ void ResetISR(void); static void NmiSR(void); static void IntDefaultHandler(void); -void SMBusMasterIntHandler1(void); -void SMBusMasterIntHandler2(void); -void SMBusMasterIntHandler3(void); -void SMBusMasterIntHandler4(void); -void SMBusMasterIntHandler6(void); -extern void UART1IntHandler(void); -extern void UART4IntHandler(void); -extern void xPortPendSVHandler(void); -extern void vPortSVCHandler(void); -extern void xPortSysTickHandler(void); -void ADCSeq0Interrupt(); -void ADCSeq1Interrupt(); /* The prototype shows it is a naked function - in effect this is just an From 0286a61e038e0254556f9db77f701aa752b13e22 Mon Sep 17 00:00:00 2001 From: Peter Wittich Date: Fri, 23 Aug 2019 17:09:02 -0400 Subject: [PATCH 2/4] interim commit of making MonitorTask more generic --- common/power_ctl.c | 2 +- projects/project2/FireFlyTask.c | 9 ++------- projects/project2/MonitorTask.h | 8 ++++++++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/common/power_ctl.c b/common/power_ctl.c index 3cc32eba..780f2c7b 100644 --- a/common/power_ctl.c +++ b/common/power_ctl.c @@ -62,7 +62,7 @@ struct gpio_pin_t oks[] = { { V_MGTY1_AVCC_OK, 4}, { V_MGTY2_AVCC_OK, 4}, { K_MGTY_AVCC_OK, 4}, - { K_MGTH_AVCC_OK, 4}, // this one is broken on S/N 001 + { K_MGTH_AVCC_OK, 4}, { K_MGTY_AVTT_OK, 5}, { K_MGTH_AVTT_OK, 5}, { V_MGTY1_AVTT_OK, 5}, diff --git a/projects/project2/FireFlyTask.c b/projects/project2/FireFlyTask.c index e5815fd2..0f6feb1a 100644 --- a/projects/project2/FireFlyTask.c +++ b/projects/project2/FireFlyTask.c @@ -44,14 +44,9 @@ void Print(const char* str); # define DPRINT(x) #endif // DEBUG_FIF -struct ff_i2c_addr_t { - char *name; - uint8_t mux_addr; // I2C address of the Mux - uint8_t mux_bit; // port of the mux; write value 0x1U< Date: Mon, 26 Aug 2019 20:28:42 -0400 Subject: [PATCH 3/4] Add Xilinx FPGA temp readout; unify DCDC and FPGA I2C monitoring Also some code cleanup and rationalization --- projects/project2/ADCMonitorTask.c | 4 +- projects/project2/CommandLineTask.c | 143 ++++++++++++++++++++++++---- projects/project2/CommandLineTask.h | 2 +- projects/project2/FireFlyTask.c | 2 +- projects/project2/FreeRTOSConfig.h | 3 +- projects/project2/MonitorTask.c | 141 +++++++++++++-------------- projects/project2/MonitorTask.h | 18 +++- projects/project2/Tasks.h | 51 ++++++++++ projects/project2/project2.c | 105 +++++++++++++------- 9 files changed, 334 insertions(+), 135 deletions(-) create mode 100644 projects/project2/Tasks.h diff --git a/projects/project2/ADCMonitorTask.c b/projects/project2/ADCMonitorTask.c index 188ecb26..c6427551 100644 --- a/projects/project2/ADCMonitorTask.c +++ b/projects/project2/ADCMonitorTask.c @@ -33,14 +33,12 @@ #include "driverlib/adc.h" #include "InterruptHandlers.h" - +#include "Tasks.h" // On Apollo the ADC range is from 0 - 2.5V. // Some signals must be scaled to fit in this range. #define ADC_MAX_VOLTAGE_RANGE 2.5 -#define ADC_CHANNEL_COUNT 21 -#define ADC_INFO_TEMP_ENTRY 20 // this needs to be manually kept correct. // a struct to hold some information about the ADC channel. struct ADC_Info_t { diff --git a/projects/project2/CommandLineTask.c b/projects/project2/CommandLineTask.c index d4efec94..1c46ebfb 100644 --- a/projects/project2/CommandLineTask.c +++ b/projects/project2/CommandLineTask.c @@ -38,6 +38,7 @@ #include "MonitorTask.h" #include "CommandLineTask.h" +#include "Tasks.h" #ifdef DEBUG_CON // prototype of mutex'd print @@ -183,7 +184,8 @@ static BaseType_t i2c_ctl_reg_r(char *m, size_t s, const char *mm) memset(data,0,MAX_BYTES*sizeof(data[0])); if ( nbytes > MAX_BYTES ) nbytes = MAX_BYTES; - snprintf(m, s, "i2c_ctl_reg_r: Read %d bytes from I2C address 0x%x, reg 0x%x\r\n", nbytes, address, reg_address); + snprintf(m, s, "i2c_ctl_reg_r: Read %d bytes from I2C address 0x%x, reg 0x%x\r\n", + nbytes, address, reg_address); Print(m); tSMBusStatus r = SMBusMasterI2CWriteRead(p_sMaster,address,&txdata,1,data,nbytes); @@ -295,7 +297,8 @@ static BaseType_t i2c_ctl_w(char *m, size_t s, const char *mm) return pdFALSE; } - snprintf(m, s, "i2cwr: Wrote to address 0x%x, value 0x%08x (%d bytes)\r\n", address, value, nbytes); + snprintf(m, s, "i2cwr: Wrote to address 0x%x, value 0x%08x (%d bytes)\r\n", + address, value, nbytes); return pdFALSE; } @@ -323,7 +326,8 @@ static BaseType_t power_ctl(char *m, size_t s, const char *mm) getLowestEnabledPSPriority()); bool ku_enable = (read_gpio_pin(TM4C_DIP_SW_1) == 1); bool vu_enable = (read_gpio_pin(TM4C_DIP_SW_2) == 1); - copied += snprintf(m+copied, s-copied, "VU_ENABLE:\t%d\r\nKU_ENABLE:\t%d\r\n", vu_enable, ku_enable); + copied += snprintf(m+copied, s-copied, "VU_ENABLE:\t%d\r\nKU_ENABLE:\t%d\r\n", + vu_enable, ku_enable); for ( int i = 0; i < N_PS_OKS; ++i ) { int j = getPSStatus(i); char *c; @@ -421,8 +425,9 @@ static BaseType_t led_ctl(char *m, size_t s, const char *mm) return pdFALSE; } - - +// TODO move this into a cleaner environment +//extern struct pm_command_t pm_command_dcdc[]; +extern struct MonitorTaskArgs_t dcdc_args; // dump monitor information static BaseType_t mon_ctl(char *m, size_t s, const char *mm) { @@ -432,18 +437,20 @@ static BaseType_t mon_ctl(char *m, size_t s, const char *mm) p1[p1l] = 0x00; // terminate strings BaseType_t i1 = strtol(p1, NULL, 10); - if ( i1 < 0 || i1 >= NCOMMANDS_PS ) { + if ( i1 < 0 || i1 >= dcdc_args.n_commands ) { snprintf(m, s, "%s: Invalid argument, must be between 0 and %d\r\n", __func__, - NCOMMANDS_PS-1); + dcdc_args.n_commands-1); return pdFALSE; } int copied = 0; - copied += snprintf(m+copied, s-copied, "%s\r\n", pm_command_dcdc[i1].name); - for (int ps = 0; ps < NSUPPLIES_PS; ++ps) { - copied += snprintf(m+copied, s-copied, "SUPPLY %d\r\n", ps); - for (int page = 0; page < NPAGES_PS; ++page ) { - float val = pm_values[ps*(NCOMMANDS_PS*NPAGES_PS)+page*NCOMMANDS_PS+i1]; + copied += snprintf(m+copied, s-copied, "%s\r\n", dcdc_args.commands[i1].name); + for (int ps = 0; ps < dcdc_args.n_devices; ++ps) { + copied += snprintf(m+copied, s-copied, "SUPPLY %s\r\n", + dcdc_args.devices[ps].name); + for (int page = 0; page < dcdc_args.n_pages; ++page ) { + float val = dcdc_args.pm_values[ps*(dcdc_args.n_commands*dcdc_args.n_pages) + +page*dcdc_args.n_commands+i1]; int tens = val; int frac = ABS((val - tens)*100.0); @@ -456,9 +463,6 @@ static BaseType_t mon_ctl(char *m, size_t s, const char *mm) return pdFALSE; } -const char* getADCname(const int i); -float getADCvalue(const int i); - // this command takes no arguments static BaseType_t adc_ctl(char *m, size_t s, const char *mm) @@ -495,7 +499,7 @@ static BaseType_t ff_ctl(char *m, size_t s, const char *mm) if ( whichff == 0 ) { copied += snprintf(m+copied, s-copied, "FF temperatures\r\n"); } - for ( ; whichff < 25; ++whichff ) { + for ( ; whichff < NFIREFLIES; ++whichff ) { int8_t val = getFFvalue(whichff); copied += snprintf(m+copied, s-copied, "%17s: %3d", getFFname(whichff), val); if ( whichff%2 == 1 ) @@ -517,6 +521,93 @@ static BaseType_t ff_ctl(char *m, size_t s, const char *mm) return pdFALSE; } +extern struct MonitorTaskArgs_t fpga_args; +// this command takes no arguments since there is only one command +// right now. +static BaseType_t fpga_ctl(char *m, size_t s, const char *mm) +{ + int copied = 0; + static int whichfpga = 0; + int howmany = fpga_args.n_devices*fpga_args.n_pages; + if ( whichfpga == 0 ) { + copied += snprintf(m+copied, s-copied, "FPGA monitors\r\n"); + copied += snprintf(m+copied, s-copied, "%s\r\n", fpga_args.commands[0].name); + } + + for ( ; whichfpga < howmany; ++whichfpga ) { + float val = fpga_args.pm_values[whichfpga]; + int tens = val; + int frac = ABS((val - tens)*100.0); + + copied += snprintf(m+copied, s-copied, "%5s: %02d.%02d", + fpga_args.devices[whichfpga].name, tens, frac); + if ( whichfpga%2 == 1 ) + copied += snprintf(m+copied, s-copied, "\r\n"); + else + copied += snprintf(m+copied, s-copied, "\t"); + if ( (s-copied ) < 20 ) { + ++whichfpga; + return pdTRUE; + } + + } + if ( whichfpga%2 ==1 ) { + m[copied++] = '\r'; + m[copied++] = '\n'; + m[copied] = '\0'; + } + whichfpga = 0; + return pdFALSE; +} + +// this command takes no arguments since there is only one command +// right now. +#define MAX(a,b) ((a)>(b)?a:b) +static BaseType_t sensor_summary(char *m, size_t s, const char *mm) +{ + int copied = 0; + // collect all sensor information + // highest temperature for each + // Firefly + // FPGA + // DCDC + // TM4C + float tm4c_temp = getADCvalue(ADC_INFO_TEMP_ENTRY); + int tens = tm4c_temp; + int frac = ABS((tm4c_temp-tens))*100.; + copied += snprintf(m+copied, s-copied, "MCU %02d.%02d\r\n", tens, frac); + // Fireflies. These are reported as ints but we are asked + // to report a float. + int8_t imax_temp = -99.0; + for ( int i = 0; i < NFIREFLIES; ++i ) { + int8_t v = getFFvalue(i); + if ( v > imax_temp ) + imax_temp = v; + } + copied += snprintf(m+copied, s-copied, "FIREFLY %02d.0\r\n", imax_temp); + // FPGAs. This is gonna bite me in the @#$#@ someday + float max_fpga = MAX(fpga_args.pm_values[0], fpga_args.pm_values[1]); + tens = max_fpga; + frac = ABS((tens-max_fpga))*100.; + copied += snprintf(m+copied, s-copied, "FPGA %02d.%02d\r\n", tens, frac); + + // DCDC. The first command is READ_TEMPERATURE_1. + // I am assuming it stays that way!!!!!!!! + float max_temp = -99.0; + for (int ps = 0; ps < dcdc_args.n_devices; ++ps ) { + for ( int page = 0; page < dcdc_args.n_pages; ++page ) { + float thistemp = dcdc_args.pm_values[ps*(dcdc_args.n_commands*dcdc_args.n_pages) + +page*dcdc_args.n_commands+0]; + if ( thistemp > max_temp ) + max_temp = thistemp; + } + } + tens = max_temp; + frac = ABS((max_temp-tens))*100.0; + copied += snprintf(m+copied, s-copied, "REG %02d.%02d\r\n", tens, frac); + + return pdFALSE; +} static void TaskGetRunTimeStats( char *pcWriteBuffer, size_t bufferLength ) @@ -752,6 +843,21 @@ CLI_Command_Definition_t ff_command = { 0 }; +static +CLI_Command_Definition_t fpga_command = { + .pcCommand="fpga", + .pcHelpString="fpga\r\n Displays a table showing the state of FPGAs.\r\n", + .pxCommandInterpreter = fpga_ctl, + 0 +}; +static +CLI_Command_Definition_t sensor_summary_command = { + .pcCommand="simple_sensor", + .pcHelpString="simple_sensor\r\n Displays a table showing the state of temps.\r\n", + .pxCommandInterpreter = sensor_summary, + 0 +}; + void vCommandLineTask( void *pvParameters ) @@ -763,7 +869,7 @@ void vCommandLineTask( void *pvParameters ) configASSERT(pvParameters != 0); - CommandLineArgs_t *args = pvParameters; + CommandLineTaskArgs_t *args = pvParameters; StreamBufferHandle_t uartStreamBuffer = args->UartStreamBuffer; uint32_t uart_base = args->uart_base; @@ -781,7 +887,8 @@ void vCommandLineTask( void *pvParameters ) FreeRTOS_CLIRegisterCommand(&monitor_command ); FreeRTOS_CLIRegisterCommand(&adc_command ); FreeRTOS_CLIRegisterCommand(&ff_command ); - + FreeRTOS_CLIRegisterCommand(&fpga_command ); + FreeRTOS_CLIRegisterCommand(&sensor_summary_command); /* Send a welcome message to the user knows they are connected. */ diff --git a/projects/project2/CommandLineTask.h b/projects/project2/CommandLineTask.h index cace7bb6..fdd8d29b 100644 --- a/projects/project2/CommandLineTask.h +++ b/projects/project2/CommandLineTask.h @@ -23,6 +23,6 @@ void vCommandLineTask(void *parameters); typedef struct { StreamBufferHandle_t UartStreamBuffer; uint32_t uart_base; -} CommandLineArgs_t; +} CommandLineTaskArgs_t; #endif /* PROJECTS_PROJECT2_COMMANDLINETASK_H_ */ diff --git a/projects/project2/FireFlyTask.c b/projects/project2/FireFlyTask.c index 0f6feb1a..f1f954e3 100644 --- a/projects/project2/FireFlyTask.c +++ b/projects/project2/FireFlyTask.c @@ -25,7 +25,7 @@ #include "common/smbus_units.h" #include "MonitorTask.h" #include "common/power_ctl.h" - +#include "Tasks.h" #define NFIREFLIES_KU15P 11 #define NFIREFLIES_VU7P 14 diff --git a/projects/project2/FreeRTOSConfig.h b/projects/project2/FreeRTOSConfig.h index c64bc3ca..fd7ae7ee 100644 --- a/projects/project2/FreeRTOSConfig.h +++ b/projects/project2/FreeRTOSConfig.h @@ -37,7 +37,7 @@ void stopwatch_reset(void); #define configMAX_PRIORITIES ( 5 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 256 ) #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 16 * 1024 ) ) -#define configMAX_TASK_NAME_LEN ( 5 ) +#define configMAX_TASK_NAME_LEN ( 6 ) #define configUSE_TRACE_FACILITY 1 #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 @@ -59,7 +59,6 @@ void stopwatch_reset(void); /* Run time stats gathering definitions. */ #define configGENERATE_RUN_TIME_STATS 1 -// Todo: this counter should be implemented to get better stats. See DWT cycle count register. #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() stopwatch_reset() #define portGET_RUN_TIME_COUNTER_VALUE() stopwatch_getticks() #define configRECORD_STACK_HIGH_ADDRESS 1 diff --git a/projects/project2/MonitorTask.c b/projects/project2/MonitorTask.c index 99fc43dc..d16ebfb9 100644 --- a/projects/project2/MonitorTask.c +++ b/projects/project2/MonitorTask.c @@ -38,43 +38,29 @@ void Print(const char* str); // Todo: rewrite to get away from awkward/bad SMBUS implementation from TI +// the PAGE command is an SMBUS standard at register 0 +#define PAGE_COMMAND 0x0 -// Beware: you need to update NCOMMANDS in header file if you change -// the number of entries in this array. -struct pm_list pm_command_dcdc[] = { - { 0x8d, 2, "READ_TEMPERATURE_1", "C", PM_LINEAR11 }, - { 0x8f, 2, "READ_TEMPERATURE_3", "C", PM_LINEAR11 }, - { 0x88, 2, "READ_VIN", "V", PM_LINEAR11 }, - { 0x8B, 2, "READ_VOUT", "V", PM_LINEAR16U }, - { 0x8c, 2, "READ_IOUT", "A", PM_LINEAR11 }, - //{ 0x4F, 2, "OT_FAULT_LIMIT", "C", PM_LINEAR11}, - { 0x79, 2, "STATUS_WORD", "", PM_STATUS }, - //{ 0xE7, 2, "IOUT_AVG_OC_FAULT_LIMIT", "A", PM_LINEAR11 }, - { 0x95, 2, "READ_FREQUENCY", "Hz", PM_LINEAR11}, -}; - -extern tSMBus g_sMaster1; - -extern tSMBusStatus eStatus1; - -float pm_values[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; -static float pm_values_max[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; -static float pm_values_min[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; - -static -void update_max() { - for (int i = 0; i < NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS; ++i ) { - if ( pm_values_max[i] < pm_values[i]) - pm_values_max[i] = pm_values[i]; - } -} -static -void update_min() { - for (int i = 0; i < NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS; ++i ) { - if ( pm_values_min[i] > pm_values[i]) - pm_values_min[i] = pm_values[i]; - } -} + + +//float pm_values[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; +//static float pm_values_max[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; +//static float pm_values_min[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; +// +//static +//void update_max(float pm_values_max[], float pm_values[], int nentries) { +// for (int i = 0; i < nentries; ++i ) { +// if ( pm_values_max[i] < pm_values[i]) +// pm_values_max[i] = pm_values[i]; +// } +//} +//static +//void update_min() { +// for (int i = 0; i < NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS; ++i ) { +// if ( pm_values_min[i] > pm_values[i]) +// pm_values_min[i] = pm_values[i]; +// } +//} // Monitor temperatures, voltages, currents, via I2C/PMBUS void MonitorTask(void *parameters) @@ -83,10 +69,12 @@ void MonitorTask(void *parameters) TickType_t xLastWakeTime = xTaskGetTickCount(); uint8_t data[2]; - for ( int i = 0; i < NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS; ++i ) { - pm_values_max[i] = -99; - pm_values_min[i] = +99; - } + struct MonitorTaskArgs_t *args = parameters; + +// for ( int i = 0; i < NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS; ++i ) { +// pm_values_max[i] = -99; +// pm_values_min[i] = +99; +// } //vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 500 ) ); vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 2500 ) ); @@ -101,11 +89,13 @@ void MonitorTask(void *parameters) // 0x43 | KVCCINT | 1 // 0x46 | VVCCINT | 1 // 0x45 | VVCCINT | 1 - const uint8_t addrs[NSUPPLIES_PS] = { 0x40, 0x44, 0x43, 0x46, 0x45}; + //const uint8_t addrs[NSUPPLIES_PS] = { 0x40, 0x44, 0x43, 0x46, 0x45}; //const uint8_t supply_prios[NSUPPLIES] = {2, 1, 1, 1, 1}; for (;;) { - //int prio = getLowestEnabledPSPriority(); + // check if the 3.3V is there or not. If it disappears then nothing works + // since that is the I2C pullups. This will be changed with next + // rev of the board. static bool good = false; if ( getPSStatus(5) != PWR_ON) { if ( good ) { @@ -118,37 +108,37 @@ void MonitorTask(void *parameters) else { good = true; } - // loop over power supplies attached to the MUX - for ( uint8_t ps = 0; ps < NSUPPLIES_PS; ++ ps ) { + // loop over devices + for ( uint8_t ps = 0; ps < args->n_devices; ++ ps ) { char tmp[64]; // select the appropriate output for the mux - data[0] = 0x1U<devices[ps].mux_bit; snprintf(tmp, 64, "MON: Output of mux set to 0x%02x\n", data[0]); DPRINT(tmp); - tSMBusStatus r = SMBusMasterI2CWrite(&g_sMaster1, 0x70U, data, 1); + tSMBusStatus r = SMBusMasterI2CWrite(args->smbus, args->devices[ps].mux_addr, data, 1); if ( r != SMBUS_OK ) { Print("MON: I2CBus command failed (setting mux)\n"); continue; } - while ( SMBusStatusGet(&g_sMaster1) == SMBUS_TRANSFER_IN_PROGRESS) { + while ( SMBusStatusGet(args->smbus) == SMBUS_TRANSFER_IN_PROGRESS) { vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 10 )); // wait } - if ( eStatus1 != SMBUS_OK ) { - snprintf(tmp, 64, "MON: Mux writing error %d, break out of loop (ps=%d) ...\n", eStatus1, ps); + if ( *args->smbus_status != SMBUS_OK ) { + snprintf(tmp, 64, "MON: Mux writing error %d, break out of loop (ps=%d) ...\n", *args->smbus_status, ps); Print(tmp); break; } - +#ifdef DEBUG_MON data[0] = 0xAAU; - r = SMBusMasterI2CRead(&g_sMaster1, 0x70U, data, 1); + r = SMBusMasterI2CRead(args->smbus, 0x70U, data, 1); if ( r != SMBUS_OK ) { Print("MON: Read of MUX output failed\n"); } - while ( SMBusStatusGet(&g_sMaster1) == SMBUS_TRANSFER_IN_PROGRESS) { + while ( SMBusStatusGet(args->smbus) == SMBUS_TRANSFER_IN_PROGRESS) { vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 10 )); // wait } - if ( eStatus1 != SMBUS_OK ) { - snprintf(tmp, 64, "MON: Mux reading error %d, break out of loop (ps=%d) ...\n", eStatus1, ps); + if ( *args->smbus_status != SMBUS_OK ) { + snprintf(tmp, 64, "MON: Mux reading error %d, break out of loop (ps=%d) ...\n", *args->smbus_status, ps); Print(tmp); break; } @@ -156,52 +146,52 @@ void MonitorTask(void *parameters) snprintf(tmp, 64, "MON: read back register on mux to be %02x\n", data[0]); DPRINT(tmp); } +#endif // DEBUG_MON // loop over pages on the supply - for ( uint8_t page = 0; page < NPAGES_PS; ++page ) { -#define PAGE_COMMAND 0x0 - r = SMBusMasterByteWordWrite(&g_sMaster1, addrs[ps], PAGE_COMMAND, + for ( uint8_t page = 0; page < args->n_pages; ++page ) { + r = SMBusMasterByteWordWrite(args->smbus, args->devices[ps].dev_addr, PAGE_COMMAND, &page, 1); if ( r != SMBUS_OK ) { Print("SMBUS command failed (setting page)\n"); } - while ( SMBusStatusGet(&g_sMaster1) == SMBUS_TRANSFER_IN_PROGRESS) { + while ( SMBusStatusGet(args->smbus) == SMBUS_TRANSFER_IN_PROGRESS) { vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 10 )); // wait } // this is checking the return from the interrupt - if (eStatus1 != SMBUS_OK ) { - snprintf(tmp, 64, "MON: Page SMBUS ERROR: %d\n", eStatus1); + if (*args->smbus_status != SMBUS_OK ) { + snprintf(tmp, 64, "MON: Page SMBUS ERROR: %d\n", *args->smbus_status); Print(tmp); } snprintf(tmp, 64, "\t\tMON: Page %d\n", page); DPRINT(tmp); // loop over commands - for (int c = 0; c < NCOMMANDS_PS; ++c ) { + for (int c = 0; c < args->n_commands; ++c ) { data[0] = 0x0U; data[1] = 0x0U; - r = SMBusMasterByteWordRead(&g_sMaster1, addrs[ps], pm_command_dcdc[c].command, - data, pm_command_dcdc[c].size); + r = SMBusMasterByteWordRead(args->smbus, args->devices[ps].dev_addr, args->commands[c].command, + data, args->commands[c].size); if ( r != SMBUS_OK ) { snprintf(tmp, 64, "MON: SMBUS failed (master/bus busy, (ps=%d,c=%d,p=%d)\n", ps,c,page); Print(tmp); continue; // abort reading this register } - while ( SMBusStatusGet(&g_sMaster1) == SMBUS_TRANSFER_IN_PROGRESS) { + while ( SMBusStatusGet(args->smbus) == SMBUS_TRANSFER_IN_PROGRESS) { vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 10 )); // wait } - if (eStatus1 != SMBUS_OK ) { - snprintf(tmp, 64, "MON: SMBUS ERROR: %d\n", eStatus1); + if (*args->smbus_status != SMBUS_OK ) { + snprintf(tmp, 64, "MON: SMBUS ERROR: %d\n", *args->smbus_status); DPRINT(tmp); } - if ( eStatus1 != SMBUS_OK ) { - snprintf(tmp, 64, "Error %d, break out of loop (ps=%d,c=%d,p=%d) ...\n", eStatus1, ps,c,page); + if ( *args->smbus_status != SMBUS_OK ) { + snprintf(tmp, 64, "Error %d, break out of loop (ps=%d,c=%d,p=%d) ...\n", *args->smbus_status, ps,c,page); Print(tmp); break; } - snprintf(tmp, 64, "MON: %d %s is 0x%02x %02x\n", ps, pm_command_dcdc[c].name, data[1], data[0]); + snprintf(tmp, 64, "MON: %d %s is 0x%02x %02x\n", ps, args->commands[c].name, data[1], data[0]); DPRINT(tmp); float val; - if ( pm_command_dcdc[c].type == PM_LINEAR11 ) { + if ( args->commands[c].type == PM_LINEAR11 ) { linear11_val_t ii; ii.raw = (data[1] << 8) | data[0]; val = linear11_to_float(ii); int tens = val; @@ -209,7 +199,7 @@ void MonitorTask(void *parameters) snprintf(tmp, 64, "\t\t%d.%02d (linear11)\n", tens, fraction); DPRINT(tmp); } - else if ( pm_command_dcdc[c].type == PM_LINEAR16U ) { + else if ( args->commands[c].type == PM_LINEAR16U ) { uint16_t ii = (data[1] << 8) | data[0]; val = linear16u_to_float(ii); int tens = val; @@ -217,20 +207,21 @@ void MonitorTask(void *parameters) snprintf(tmp, 64, "\t\t%d.%02d (linear16u)\n", tens, fraction); DPRINT(tmp); } - else if ( pm_command_dcdc[c].type == PM_STATUS ) { + else if ( args->commands[c].type == PM_STATUS ) { + // todo: this assumes 2 byte xfer and endianness and converts and int to a float val = (float)((data[1] << 8) | data[0]); // ugly is my middle name } else { val = -99.0; // should never get here } - int index = ps*(NCOMMANDS_PS*NPAGES_PS)+page*NCOMMANDS_PS+c; - pm_values[index] = val; + int index = ps*(args->n_commands*args->n_pages)+page*args->n_commands+c; + args->pm_values[index] = val; // wait here for the x msec, where x is 2nd argument below. vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 10 ) ); } // loop over commands } // loop over pages } // loop over power supplies - update_max(); update_min(); + //update_max(pm_values_max, args->pm_values, args->n_values); update_min(); vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 250 ) ); } // infinite loop diff --git a/projects/project2/MonitorTask.h b/projects/project2/MonitorTask.h index a0b1cd3f..c64013b6 100644 --- a/projects/project2/MonitorTask.h +++ b/projects/project2/MonitorTask.h @@ -8,6 +8,8 @@ #ifndef PROJECTS_PROJECT2_MONITORTASK_H_ #define PROJECTS_PROJECT2_MONITORTASK_H_ +#include "common/smbus.h" + extern float pm_values[]; #define ABS(x) ((x)<0?(-(x)):(x)) @@ -15,7 +17,7 @@ extern float pm_values[]; // pilfered and adapted from http://billauer.co.il/blog/2018/01/c-pmbus-xilinx-fpga-kc705/ enum { PM_VOLTAGE, PM_NONVOLTAGE, PM_STATUS, PM_LINEAR11, PM_LINEAR16U, PM_LINEAR16S } pm_types ; -struct pm_list { +struct pm_command_t { unsigned char command; int size; char *name; @@ -31,11 +33,23 @@ struct dev_i2c_addr_t { uint8_t dev_addr; // I2C address of device. }; +struct MonitorTaskArgs_t { + const char *name; + struct dev_i2c_addr_t * devices; + const int n_devices; + struct pm_command_t * commands; + const int n_commands; + float *pm_values; + const int n_values; + const int n_pages; + tSMBus *smbus; + volatile tSMBusStatus *smbus_status; +}; + #define NSUPPLIES_PS (5) // 5 devices, 2 pages each #define NCOMMANDS_PS 7 // number of entries in above array #define NPAGES_PS 2 // number of pages on the power supplies. -extern struct pm_list pm_command_dcdc[]; #endif /* PROJECTS_PROJECT2_MONITORTASK_H_ */ diff --git a/projects/project2/Tasks.h b/projects/project2/Tasks.h new file mode 100644 index 00000000..993965bc --- /dev/null +++ b/projects/project2/Tasks.h @@ -0,0 +1,51 @@ +/* + * Tasks.h + * + * Created on: Aug 26, 2019 + * Author: pw94 + * + * Header file for tasks and associated functions, for those tasks + * where a dedicated header file would be overkill. + */ + +#ifndef PROJECTS_PROJECT2_TASKS_H_ +#define PROJECTS_PROJECT2_TASKS_H_ + +#include "FreeRTOS.h" +#include "FreeRTOSConfig.h" +#include "queue.h" + +// ADC task +#define ADC_CHANNEL_COUNT 21 +#define ADC_INFO_TEMP_ENTRY 20 // this needs to be manually kept correct. + +const char* getADCname(const int i); +float getADCvalue(const int i); + +// Holds the handle of the created queue for the LED task. +extern QueueHandle_t xLedQueue; + +// control the LED +void LedTask(void *parameters); + +// Holds the handle of the created queue for the power supply task. +extern QueueHandle_t xPwrQueue; + + +// monitor and control the power supplies +void PowerSupplyTask(void *parameters); +void MonitorTask(void *parameters); + +// firefly monitoring +#define NFIREFLIES_KU15P 11 +#define NFIREFLIES_VU7P 14 +#define NFIREFLIES (NFIREFLIES_KU15P+NFIREFLIES_VU7P) + +void FireFlyTask(void *parameters); + + + +// Monitoring using the ADC inputs +void ADCMonitorTask(void *parameters); + +#endif /* PROJECTS_PROJECT2_TASKS_H_ */ diff --git a/projects/project2/project2.c b/projects/project2/project2.c index fcb808d7..c4a487d2 100644 --- a/projects/project2/project2.c +++ b/projects/project2/project2.c @@ -26,6 +26,8 @@ #include "common/smbus.h" #include "CommandLineTask.h" #include "InterruptHandlers.h" +#include "MonitorTask.h" +#include "Tasks.h" // TI Includes #include "inc/hw_types.h" @@ -213,27 +215,7 @@ volatile uint32_t g_ui32SysTickCount; -// Holds the handle of the created queue for the LED task. -extern QueueHandle_t xLedQueue; -// control the LED -void LedTask(void *parameters); - -// Holds the handle of the created queue for the power supply task. -extern QueueHandle_t xPwrQueue; - - -// monitor and control the power supplies -void PowerSupplyTask(void *parameters); -void MonitorTask(void *parameters); - -// firefly monitoring -void FireFlyTask(void *parameters); - - - -// Monitoring using the ADC inputs -void ADCMonitorTask(void *parameters); void ShortDelay() { @@ -258,10 +240,65 @@ void vGetTaskHandle( char *key, TaskHandle_t *t) return ; } -CommandLineArgs_t cli_uart1; -CommandLineArgs_t cli_uart4; - - +CommandLineTaskArgs_t cli_uart1; +CommandLineTaskArgs_t cli_uart4; + +struct dev_i2c_addr_t fpga_addrs[] = { + {"VU7P", 0x70, 1, 0x36}, + {"KU15P", 0x70, 0, 0x36}, +}; +struct pm_command_t pm_command_fpga[] = { + { 0x8d, 2, "READ_TEMPERATURE_1", "C", PM_LINEAR11 }, +}; + +float pm_fpga[2] = {0.0,0.0}; + +struct MonitorTaskArgs_t fpga_args = { + .name = "FMON", + .devices = fpga_addrs, + .n_devices = 2, + .commands = pm_command_fpga, + .n_commands = 1, + .pm_values = pm_fpga, + .n_values = 2, + .n_pages = 1, + .smbus = &g_sMaster6, + .smbus_status = &eStatus6, +}; + +struct dev_i2c_addr_t pm_addrs_dcdc[] = { + {"3V3/1V8", 0x70, 0, 0x40}, + {"KVCCINT1", 0x70, 1, 0x44}, + {"KVCCINT2", 0x70, 2, 0x43}, + {"VVCCINT1", 0x70, 3, 0x46}, + {"VVCCINT2", 0x70, 4, 0x45}, +}; + + +struct pm_command_t pm_command_dcdc[] = { + { 0x8d, 2, "READ_TEMPERATURE_1", "C", PM_LINEAR11 }, + { 0x8f, 2, "READ_TEMPERATURE_3", "C", PM_LINEAR11 }, + { 0x88, 2, "READ_VIN", "V", PM_LINEAR11 }, + { 0x8B, 2, "READ_VOUT", "V", PM_LINEAR16U }, + { 0x8c, 2, "READ_IOUT", "A", PM_LINEAR11 }, + //{ 0x4F, 2, "OT_FAULT_LIMIT", "C", PM_LINEAR11}, + { 0x79, 2, "STATUS_WORD", "", PM_STATUS }, + //{ 0xE7, 2, "IOUT_AVG_OC_FAULT_LIMIT", "A", PM_LINEAR11 }, + { 0x95, 2, "READ_FREQUENCY", "Hz", PM_LINEAR11}, + }; +float dcdc_values[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; +struct MonitorTaskArgs_t dcdc_args = { + .name = "VMON", + .devices = pm_addrs_dcdc, + .n_devices = 5, + .commands = pm_command_dcdc, + .n_commands = 7, + .pm_values = dcdc_values, + .n_values = NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS, + .n_pages = 2, + .smbus = &g_sMaster1, + .smbus_status = &eStatus1, +}; // int main( void ) @@ -284,19 +321,21 @@ int main( void ) // start the tasks here xTaskCreate(PowerSupplyTask, "POW", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+5, &TaskNamePairs[0].value); xTaskCreate(LedTask, "LED", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+2, &TaskNamePairs[1].value); - xTaskCreate(vCommandLineTask,"CL1", 512, &cli_uart1, tskIDLE_PRIORITY+1, &TaskNamePairs[2].value); - xTaskCreate(vCommandLineTask,"CL4", 512, &cli_uart4, tskIDLE_PRIORITY+1, &TaskNamePairs[3].value); + xTaskCreate(vCommandLineTask,"CLIZY", 512, &cli_uart1, tskIDLE_PRIORITY+1, &TaskNamePairs[2].value); + xTaskCreate(vCommandLineTask,"CLIFP", 512, &cli_uart4, tskIDLE_PRIORITY+1, &TaskNamePairs[3].value); xTaskCreate(ADCMonitorTask, "ADC", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+4, &TaskNamePairs[4].value); - xTaskCreate(MonitorTask, "MON", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+4, &TaskNamePairs[5].value); - xTaskCreate(FireFlyTask, "FLY", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+4, &TaskNamePairs[6].value); + xTaskCreate(FireFlyTask, "FFLY", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+4, &TaskNamePairs[6].value); + xTaskCreate(MonitorTask, "PSMON", configMINIMAL_STACK_SIZE, &dcdc_args, tskIDLE_PRIORITY+4, &TaskNamePairs[5].value); + xTaskCreate(MonitorTask, "XIMON", configMINIMAL_STACK_SIZE, &fpga_args, tskIDLE_PRIORITY+4, &TaskNamePairs[7].value); snprintf(TaskNamePairs[0].key,configMAX_TASK_NAME_LEN,"POW"); snprintf(TaskNamePairs[1].key,configMAX_TASK_NAME_LEN,"LED"); - snprintf(TaskNamePairs[2].key,configMAX_TASK_NAME_LEN,"CL1"); - snprintf(TaskNamePairs[3].key,configMAX_TASK_NAME_LEN,"CL4"); + snprintf(TaskNamePairs[2].key,configMAX_TASK_NAME_LEN,"CLIZY"); + snprintf(TaskNamePairs[3].key,configMAX_TASK_NAME_LEN,"CLIFP"); snprintf(TaskNamePairs[4].key,configMAX_TASK_NAME_LEN,"ADC"); - snprintf(TaskNamePairs[5].key,configMAX_TASK_NAME_LEN,"MON"); - snprintf(TaskNamePairs[6].key,configMAX_TASK_NAME_LEN,"FLY"); + snprintf(TaskNamePairs[5].key,configMAX_TASK_NAME_LEN,"PSMON"); + snprintf(TaskNamePairs[6].key,configMAX_TASK_NAME_LEN,"FFLY"); + snprintf(TaskNamePairs[7].key,configMAX_TASK_NAME_LEN,"XIMON"); // queue for the LED xLedQueue = xQueueCreate(5, // The maximum number of items the queue can hold. @@ -316,7 +355,7 @@ int main( void ) Print("\n\r----------------------------\n\r"); Print("Staring Project2 " FIRMWARE_VERSION " (FreeRTOS scheduler about to start)\n\r"); - Print("Built at " __TIME__", " __DATE__ "\n\r"); + Print("Built on " __TIME__", " __DATE__ "\n\r"); Print( "----------------------------\n\r"); // start the scheduler -- this function should not return vTaskStartScheduler(); From 0bb18bccaac471e2c45b038fe0d906bc0e029137 Mon Sep 17 00:00:00 2001 From: Peter Wittich Date: Tue, 27 Aug 2019 15:55:28 -0400 Subject: [PATCH 4/4] Add alarm task Alarm task shuts off when temperature hits a critical value also code cleanup --- common/power_ctl.c | 8 +- common/power_ctl.h | 10 ++- projects/project2/AlarmTask.c | 126 ++++++++++++++++++++++++++++ projects/project2/CommandLineTask.c | 90 +++++++++++++++----- projects/project2/Makefile | 7 ++ projects/project2/MonitorTask.c | 68 +++++---------- projects/project2/MonitorTask.h | 5 +- projects/project2/PowerSupplyTask.c | 12 ++- projects/project2/Tasks.h | 34 +++++++- projects/project2/project2.c | 39 +++++++-- 10 files changed, 312 insertions(+), 87 deletions(-) create mode 100644 projects/project2/AlarmTask.c diff --git a/common/power_ctl.c b/common/power_ctl.c index 780f2c7b..05ee4cdb 100644 --- a/common/power_ctl.c +++ b/common/power_ctl.c @@ -71,7 +71,7 @@ struct gpio_pin_t oks[] = { const int num_priorities = 5; // this array states[] holds the current status of these power supplies -static enum ps_state states[N_PS_OKS] = { UNKNOWN }; +static enum ps_state states[N_PS_OKS] = { PWR_UNKNOWN }; // this variable holds the current lowest enabled power supply static int lowest_enabled_ps_prio = 0; @@ -83,7 +83,7 @@ int getLowestEnabledPSPriority() enum ps_state getPSStatus(int i) { - if ( i < 0 || i >= N_PS_OKS) return UNKNOWN; + if ( i < 0 || i >= N_PS_OKS) return PWR_UNKNOWN; return states[i]; } void setPSStatus(int i, enum ps_state theState) @@ -214,7 +214,7 @@ check_ps(void) } // find out if any of the failures are new failures or not for ( int o = 0; o < N_PS_OKS; ++o ) { - if ( new_states[o] != states[o] && states[o] != UNKNOWN) { + if ( new_states[o] != states[o] && states[o] != PWR_UNKNOWN) { static char tmp[128]; snprintf(tmp, 128, "check_ps: New failed supply %s (level %d)\n", pin_names[oks[o].name], oks[o].priority); @@ -276,7 +276,7 @@ disable_ps(void) int8_t val = read_gpio_pin(oks[o].name); if ( val == 1 ) { all_ready = false; - states[o] = UNKNOWN; + states[o] = PWR_UNKNOWN; } } } // loop over 'ok' bits diff --git a/common/power_ctl.h b/common/power_ctl.h index 19828e22..ba7adce3 100644 --- a/common/power_ctl.h +++ b/common/power_ctl.h @@ -18,6 +18,14 @@ #define PS_OFF (4) #define PS_ERROR (5) // error generated by pwr_ctl #define PS_STATUS (6) +// alarms +#define TEMP_ALARM (7) +#define TEMP_ALARM_CLEAR (8) +#define CURRENT_ALARM (9) +#define CURRENT_ALAMR_CLEAR (10) + +// alarms + // this should go elsewhere #define RED_LED_OFF (25) #define RED_LED_ON (26) @@ -27,7 +35,7 @@ #define HUH (99) -enum ps_state { UNKNOWN, PWR_ON, PWR_OFF, DISABLED }; +enum ps_state { PWR_UNKNOWN, PWR_ON, PWR_OFF, DISABLED }; enum ps_state getPSStatus(int i); void setPSStatus(int i, enum ps_state theState); int getLowestEnabledPSPriority(); diff --git a/projects/project2/AlarmTask.c b/projects/project2/AlarmTask.c new file mode 100644 index 00000000..07975b3d --- /dev/null +++ b/projects/project2/AlarmTask.c @@ -0,0 +1,126 @@ +/* + * AlarmTask.c + * + * Created on: Aug 26, 2019 + * Author: pw94 + * + * This task monitors the temperatures (and maybe other quantities in the + * future) and dispatches alarms if it deems fit. + * + * The alarms currently are not cleared except by restarting the MCU or + * by sending a message from the console. + */ +#include "Tasks.h" +#include "MonitorTask.h" +#include "common/power_ctl.h" + + + +// this queue is used to receive messages +QueueHandle_t xAlmQueue; + +enum temp_state {TEMP_UNKNOWN, TEMP_GOOD, TEMP_BAD}; + +enum alarm_state {ALM_UNKNOWN, ALM_GOOD, ALM_BAD}; + + + +// Status of the alarm task +static uint32_t status = 0x0; + +// read-only, so no need to use queue +uint32_t getAlarmStatus() +{ + return status; +} + +#define INITIAL_ALARM_TEMP 55.0 // in Celsius duh +static float alarm_temp = INITIAL_ALARM_TEMP; + +float getAlarmTemperature() +{ + return alarm_temp; +} + +void setAlarmTemperature(const float newtemp) +{ + alarm_temp = newtemp; + return; +} + + +void AlarmTask(void *parameters) +{ + // initialize to the current tick time + TickType_t xLastWakeTime = xTaskGetTickCount(); + uint32_t message; // this must be in a semi-permanent scope + enum temp_state current_temp_state = TEMP_UNKNOWN; + + vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 2500 ) ); + + + for (;;) { + vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 25 ) ); + + if ( xQueueReceive(xAlmQueue, &message, 0) ) { + switch (message) { + case TEMP_ALARM_CLEAR_ALL: + status = 0; + break; + case TEMP_ALARM_CLEAR_FPGA: // this is an example + status &= ~ALM_STAT_FPGA_OVERTEMP; + break; + default: + break; + } + continue; // we break out of the loop because we want data + // to refresh + } + + + // microcontroller + float tm4c_temp = getADCvalue(ADC_INFO_TEMP_ENTRY); + if ( tm4c_temp > alarm_temp ) status |= ALM_STAT_TM4C_OVERTEMP; + // FPGA + float max_fpga = MAX(fpga_args.pm_values[0], fpga_args.pm_values[1]); + if ( max_fpga > alarm_temp) status |= ALM_STAT_FPGA_OVERTEMP; + + // DCDC. The first command is READ_TEMPERATURE_1. + // I am assuming it stays that way!!!!!!!! + float max_dcdc_temp = -99.0; + for (int ps = 0; ps < dcdc_args.n_devices; ++ps ) { + for ( int page = 0; page < dcdc_args.n_pages; ++page ) { + float thistemp = dcdc_args.pm_values[ps*(dcdc_args.n_commands*dcdc_args.n_pages) + +page*dcdc_args.n_commands+0]; + if ( thistemp > max_dcdc_temp ) + max_dcdc_temp = thistemp; + } + } + if ( max_dcdc_temp > alarm_temp ) status |= ALM_STAT_DCDC_OVERTEMP; + // Fireflies. These are reported as ints but we are asked + // to report a float. + int8_t imax_ff_temp = -99; + for ( int i = 0; i < NFIREFLIES; ++i ) { + int8_t v = getFFvalue(i); + if ( v > imax_ff_temp ) + imax_ff_temp = v; + } + if ( (float)imax_ff_temp > alarm_temp ) status |= ALM_STAT_FIREFLY_OVERTEMP; + + if ( status && current_temp_state != TEMP_BAD ) { + message = TEMP_ALARM; + xQueueSendToFront(xPwrQueue, &message, pdMS_TO_TICKS(100)); + current_temp_state = TEMP_BAD; + } + else if ( !status && current_temp_state == TEMP_BAD ) { + message = TEMP_ALARM_CLEAR; + xQueueSendToFront(xPwrQueue, &message, pdMS_TO_TICKS(100)); + current_temp_state = TEMP_GOOD; + } + else { + current_temp_state = TEMP_GOOD; + } + + } + return; +} diff --git a/projects/project2/CommandLineTask.c b/projects/project2/CommandLineTask.c index 1c46ebfb..24654d6f 100644 --- a/projects/project2/CommandLineTask.c +++ b/projects/project2/CommandLineTask.c @@ -52,10 +52,6 @@ void Print(const char* str); // local sprintf prototype int snprintf( char *buf, unsigned int count, const char *format, ... ); -// external definition -extern QueueHandle_t xPwrQueue; -extern QueueHandle_t xLedQueue; - #define MAX_INPUT_LENGTH 50 #define MAX_OUTPUT_LENGTH 512 @@ -364,6 +360,63 @@ static BaseType_t power_ctl(char *m, size_t s, const char *mm) return pdFALSE; } +// takes one argument +static BaseType_t alarm_ctl(char *m, size_t s, const char *mm) +{ + int8_t *p1, *p2; + BaseType_t p1l, p2l; + p1 = FreeRTOS_CLIGetParameter(mm, 1, &p1l); + p2 = FreeRTOS_CLIGetParameter(mm, 2, &p2l); + if ( p1 == NULL ) { + snprintf(m, s, "%s: need one or more arguments\r\n", __func__); + return pdFALSE; + } + p1[p1l] = 0x00; // terminate strings + + uint32_t message; + if ( strcmp(p1, "clear") == 0 ) { + message = TEMP_ALARM_CLEAR_ALL; // turn on power supply + xQueueSendToBack(xAlmQueue, &message, pdMS_TO_TICKS(10)); + m[0] = '\0'; // no output from this command + + return pdFALSE; + } + else if ( strcmp(p1, "status") == 0 ) { // report status to UART + int copied = 0; + copied += snprintf(m+copied,s-copied, "%s: ALARM status\r\n", __func__); + int32_t stat = getAlarmStatus(); + float val = getAlarmTemperature(); + int tens = val; int frac = ABS((tens-val))*100; + copied += snprintf(m+copied, s-copied, "Temperature threshold: %02d.%02d\n\r", + tens,frac); + copied += snprintf(m+copied, s-copied, "Raw: 0x%08x\r\n", stat); + copied += snprintf(m+copied, s-copied, "TEMP TM4C: %s\r\n", + stat&ALM_STAT_TM4C_OVERTEMP?"ALARM":"GOOD"); + copied += snprintf(m+copied, s-copied, "TEMP FPGA: %s\r\n", + stat&ALM_STAT_FPGA_OVERTEMP?"ALARM":"GOOD"); + copied += snprintf(m+copied, s-copied, "TEMP FFLY: %s\r\n", + stat&ALM_STAT_FIREFLY_OVERTEMP?"ALARM":"GOOD"); + copied += snprintf(m+copied, s-copied, "TEMP DCDC: %s\r\n", + stat&ALM_STAT_DCDC_OVERTEMP?"ALARM":"GOOD"); + return pdFALSE; + } + else if ( strcmp(p1, "settemp") == 0 ) { + p2[p2l] = 0x00; // terminate strings + char *ptr; + float newtemp = strtol((const char*)p2,&ptr,10); + setAlarmTemperature(newtemp); + snprintf(m,s, "%s: set alarm temperature to %s\r\n", __func__, p2); + return pdFALSE; + } + else { + snprintf(m, s, "%s: invalid argument %s received\r\n", __func__, p1); + return pdFALSE; + } + + return pdFALSE; +} + + static BaseType_t i2c_scan(char *m, size_t s, const char *mm) @@ -425,9 +478,6 @@ static BaseType_t led_ctl(char *m, size_t s, const char *mm) return pdFALSE; } -// TODO move this into a cleaner environment -//extern struct pm_command_t pm_command_dcdc[]; -extern struct MonitorTaskArgs_t dcdc_args; // dump monitor information static BaseType_t mon_ctl(char *m, size_t s, const char *mm) { @@ -487,9 +537,6 @@ static BaseType_t adc_ctl(char *m, size_t s, const char *mm) return pdFALSE; } -const char* getFFname(const uint8_t i); -int8_t getFFvalue(const uint8_t i); - // this command takes no arguments static BaseType_t ff_ctl(char *m, size_t s, const char *mm) @@ -521,7 +568,6 @@ static BaseType_t ff_ctl(char *m, size_t s, const char *mm) return pdFALSE; } -extern struct MonitorTaskArgs_t fpga_args; // this command takes no arguments since there is only one command // right now. static BaseType_t fpga_ctl(char *m, size_t s, const char *mm) @@ -562,7 +608,6 @@ static BaseType_t fpga_ctl(char *m, size_t s, const char *mm) // this command takes no arguments since there is only one command // right now. -#define MAX(a,b) ((a)>(b)?a:b) static BaseType_t sensor_summary(char *m, size_t s, const char *mm) { int copied = 0; @@ -796,6 +841,15 @@ CLI_Command_Definition_t pwr_ctl_command = { .pxCommandInterpreter = power_ctl, 1 }; +static +CLI_Command_Definition_t alm_ctl_command = { + .pcCommand="alm", + .pcHelpString="alm (clear|status|settemp #)\r\n Get or clear status of alarm task.\r\n", + .pxCommandInterpreter = alarm_ctl, + -1 // variable number of commands +}; + + static CLI_Command_Definition_t led_ctl_command = { .pcCommand="led", @@ -889,11 +943,12 @@ void vCommandLineTask( void *pvParameters ) FreeRTOS_CLIRegisterCommand(&ff_command ); FreeRTOS_CLIRegisterCommand(&fpga_command ); FreeRTOS_CLIRegisterCommand(&sensor_summary_command); + FreeRTOS_CLIRegisterCommand(&alm_ctl_command ); /* Send a welcome message to the user knows they are connected. */ - UARTPrint(uart_base,pcWelcomeMessage); - UARTPrint(uart_base,"% "); + UARTPrint(uart_base, pcWelcomeMessage); + UARTPrint(uart_base, "% "); for( ;; ) { /* This implementation reads a single character at a time. Wait in the @@ -901,14 +956,7 @@ void vCommandLineTask( void *pvParameters ) xStreamBufferReceive(uartStreamBuffer, &cRxedChar, 1, portMAX_DELAY); UARTCharPut(uart_base, cRxedChar); // TODO this should use the Mutex - // TODO: on lnx231 the terminal _only_ sends a \r which I did not think was possible. - // on some platforms (Mac) I think this will cause the command to be sent 2x. - // this should be set in the terminal client if( cRxedChar == '\n' || cRxedChar == '\r' ) { - /* A newline character was received, so the input command string is - complete and can be processed. Transmit a line separator, just to - make the output easier to read. */ - //UARTPrint(uart_base,"\r\n"); if ( cInputIndex != 0 ) { // empty command -- skip snprintf(pcOutputString, MAX_OUTPUT_LENGTH, "Calling command >%s<\r\n", diff --git a/projects/project2/Makefile b/projects/project2/Makefile index bc316137..e0dae866 100644 --- a/projects/project2/Makefile +++ b/projects/project2/Makefile @@ -90,6 +90,7 @@ ${COMPILER}/project2.axf: ${COMPILER}/PowerSupplyTask.o ${COMPILER}/project2.axf: ${COMPILER}/ADCMonitorTask.o ${COMPILER}/project2.axf: ${COMPILER}/MonitorTask.o ${COMPILER}/project2.axf: ${COMPILER}/FireFlyTask.o +${COMPILER}/project2.axf: ${COMPILER}/AlarmTask.o ${COMPILER}/project2.axf: ${COMPILER}/LedTask.o ${COMPILER}/project2.axf: ${COMPILER}/InterruptHandlers.o ${COMPILER}/project2.axf: ${COMPILER}/startup_${COMPILER}.o @@ -110,6 +111,12 @@ SCATTERgcc_project2=project2.ld ENTRY_project2=ResetISR CFLAGSgcc=-DTARGET_IS_TM4C129_RA1 -DUSE_FREERTOS +# this rule forces the main function to be recompiled when +# any of the dependencies are out of date, to get the +# git and compile time info right. +SRCS=$(shell ls *.c ../../common/*.c) +HDRS=$(shell ls *.h ../../common/*.h) +${COMPILER}/project2.o: ${SRCS} ${HDRS} # # Include the automatically generated dependency files. # diff --git a/projects/project2/MonitorTask.c b/projects/project2/MonitorTask.c index d16ebfb9..dda58a7a 100644 --- a/projects/project2/MonitorTask.c +++ b/projects/project2/MonitorTask.c @@ -3,6 +3,12 @@ * * Created on: May 19, 2019 * Author: wittich + * + * Monitor temperatures, voltages, currents, via I2C/PMBUS. Generic, + * pass in addresses via parameter to the task. + * + * It only handles PMBUS, not raw I2C. + * */ // includes for types @@ -43,26 +49,8 @@ void Print(const char* str); -//float pm_values[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; -//static float pm_values_max[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; -//static float pm_values_min[NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS]; -// -//static -//void update_max(float pm_values_max[], float pm_values[], int nentries) { -// for (int i = 0; i < nentries; ++i ) { -// if ( pm_values_max[i] < pm_values[i]) -// pm_values_max[i] = pm_values[i]; -// } -//} -//static -//void update_min() { -// for (int i = 0; i < NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS; ++i ) { -// if ( pm_values_min[i] > pm_values[i]) -// pm_values_min[i] = pm_values[i]; -// } -//} - -// Monitor temperatures, voltages, currents, via I2C/PMBUS + + void MonitorTask(void *parameters) { // initialize to the current tick time @@ -71,26 +59,9 @@ void MonitorTask(void *parameters) struct MonitorTaskArgs_t *args = parameters; -// for ( int i = 0; i < NSUPPLIES_PS*NPAGES_PS*NCOMMANDS_PS; ++i ) { -// pm_values_max[i] = -99; -// pm_values_min[i] = +99; -// } - - //vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 500 ) ); - vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 2500 ) ); - - // these I2C addresses correspond to the addresses of the power supplies hanging - // off the TM4C PWR I2C bus - // TODO: clean up this information and collect in one place - // Supply Address | Voltages | Priority - // ---------------+----------|----------- - // 0x40 | 3.3 & 1.8| 2 - // 0x44 | KVCCINT | 1 - // 0x43 | KVCCINT | 1 - // 0x46 | VVCCINT | 1 - // 0x45 | VVCCINT | 1 - //const uint8_t addrs[NSUPPLIES_PS] = { 0x40, 0x44, 0x43, 0x46, 0x45}; - //const uint8_t supply_prios[NSUPPLIES] = {2, 1, 1, 1, 1}; + + //vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 2500 ) ); + for (;;) { // check if the 3.3V is there or not. If it disappears then nothing works @@ -124,7 +95,8 @@ void MonitorTask(void *parameters) vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 10 )); // wait } if ( *args->smbus_status != SMBUS_OK ) { - snprintf(tmp, 64, "MON: Mux writing error %d, break out of loop (ps=%d) ...\n", *args->smbus_status, ps); + snprintf(tmp, 64, "MON: Mux writing error %d, break out of loop (ps=%d) ...\n", + *args->smbus_status, ps); Print(tmp); break; } @@ -138,7 +110,8 @@ void MonitorTask(void *parameters) vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 10 )); // wait } if ( *args->smbus_status != SMBUS_OK ) { - snprintf(tmp, 64, "MON: Mux reading error %d, break out of loop (ps=%d) ...\n", *args->smbus_status, ps); + snprintf(tmp, 64, "MON: Mux reading error %d, break out of loop (ps=%d) ...\n", + *args->smbus_status, ps); Print(tmp); break; } @@ -169,8 +142,8 @@ void MonitorTask(void *parameters) for (int c = 0; c < args->n_commands; ++c ) { data[0] = 0x0U; data[1] = 0x0U; - r = SMBusMasterByteWordRead(args->smbus, args->devices[ps].dev_addr, args->commands[c].command, - data, args->commands[c].size); + r = SMBusMasterByteWordRead(args->smbus, args->devices[ps].dev_addr, + args->commands[c].command, data, args->commands[c].size); if ( r != SMBUS_OK ) { snprintf(tmp, 64, "MON: SMBUS failed (master/bus busy, (ps=%d,c=%d,p=%d)\n", ps,c,page); Print(tmp); @@ -184,11 +157,13 @@ void MonitorTask(void *parameters) DPRINT(tmp); } if ( *args->smbus_status != SMBUS_OK ) { - snprintf(tmp, 64, "Error %d, break out of loop (ps=%d,c=%d,p=%d) ...\n", *args->smbus_status, ps,c,page); + snprintf(tmp, 64, "Error %d, break out of loop (ps=%d,c=%d,p=%d) ...\n", + *args->smbus_status, ps,c,page); Print(tmp); break; } - snprintf(tmp, 64, "MON: %d %s is 0x%02x %02x\n", ps, args->commands[c].name, data[1], data[0]); + snprintf(tmp, 64, "MON: %d %s is 0x%02x %02x\n", ps, args->commands[c].name, + data[1], data[0]); DPRINT(tmp); float val; if ( args->commands[c].type == PM_LINEAR11 ) { @@ -221,7 +196,6 @@ void MonitorTask(void *parameters) } // loop over commands } // loop over pages } // loop over power supplies - //update_max(pm_values_max, args->pm_values, args->n_values); update_min(); vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 250 ) ); } // infinite loop diff --git a/projects/project2/MonitorTask.h b/projects/project2/MonitorTask.h index c64013b6..4008c194 100644 --- a/projects/project2/MonitorTask.h +++ b/projects/project2/MonitorTask.h @@ -45,11 +45,14 @@ struct MonitorTaskArgs_t { tSMBus *smbus; volatile tSMBusStatus *smbus_status; }; - +// DC-DC converter #define NSUPPLIES_PS (5) // 5 devices, 2 pages each #define NCOMMANDS_PS 7 // number of entries in above array #define NPAGES_PS 2 // number of pages on the power supplies. +extern struct MonitorTaskArgs_t dcdc_args; +extern struct MonitorTaskArgs_t fpga_args; + #endif /* PROJECTS_PROJECT2_MONITORTASK_H_ */ diff --git a/projects/project2/PowerSupplyTask.c b/projects/project2/PowerSupplyTask.c index c7a2b04d..7ba9a435 100644 --- a/projects/project2/PowerSupplyTask.c +++ b/projects/project2/PowerSupplyTask.c @@ -38,7 +38,8 @@ void PowerSupplyTask(void *parameters) { // initialize to the current tick time TickType_t xLastWakeTime = xTaskGetTickCount(); - enum ps_state oldState = UNKNOWN; + enum ps_state oldState = PWR_UNKNOWN; + bool alarm = false; // turn on the power supply at the start of the task, if the power enable is sent by the // zynq @@ -55,6 +56,13 @@ void PowerSupplyTask(void *parameters) case PS_OFF: disable_ps(); break; + case TEMP_ALARM: + alarm = true; + disable_ps(); + break; + case TEMP_ALARM_CLEAR: + alarm = false; + break; case PS_ON: set_ps(); break; @@ -75,7 +83,7 @@ void PowerSupplyTask(void *parameters) disable_ps(); newstate = PWR_OFF; } - else { // blade_power_enable + else if ( ! alarm ) { // blade_power_enable and not alarm set_ps(); newstate = PWR_ON; } diff --git a/projects/project2/Tasks.h b/projects/project2/Tasks.h index 993965bc..09e2300d 100644 --- a/projects/project2/Tasks.h +++ b/projects/project2/Tasks.h @@ -15,6 +15,9 @@ #include "FreeRTOSConfig.h" #include "queue.h" + #define MAX(a,b) (a)>(b)?(a):(b) + + // ADC task #define ADC_CHANNEL_COUNT 21 #define ADC_INFO_TEMP_ENTRY 20 // this needs to be manually kept correct. @@ -29,20 +32,43 @@ extern QueueHandle_t xLedQueue; void LedTask(void *parameters); // Holds the handle of the created queue for the power supply task. -extern QueueHandle_t xPwrQueue; - -// monitor and control the power supplies +// --- Power Supply management task void PowerSupplyTask(void *parameters); +extern QueueHandle_t xPwrQueue; + +// --- Semi-generic PMBUS based I2C task void MonitorTask(void *parameters); -// firefly monitoring +// --- Firefly monitoring #define NFIREFLIES_KU15P 11 #define NFIREFLIES_VU7P 14 #define NFIREFLIES (NFIREFLIES_KU15P+NFIREFLIES_VU7P) void FireFlyTask(void *parameters); +const char* getFFname(const uint8_t i); +int8_t getFFvalue(const uint8_t i); + + +// ---- ALARMS + +// status register bits +#define ALM_STAT_TM4C_OVERTEMP 0x1 +#define ALM_STAT_FIREFLY_OVERTEMP 0x2 +#define ALM_STAT_FPGA_OVERTEMP 0x4 +#define ALM_STAT_DCDC_OVERTEMP 0x8 +// Alarm Queue +extern QueueHandle_t xAlmQueue; +// messages +#define TEMP_ALARM_CLEAR_ALL 1 +#define TEMP_ALARM_CLEAR_FPGA 2 // ... + + +void AlarmTask(void *parameters); +float getAlarmTemperature(); +void setAlarmTemperature(const float); +uint32_t getAlarmStatus(); // Monitoring using the ADC inputs diff --git a/projects/project2/project2.c b/projects/project2/project2.c index c4a487d2..44c3f053 100644 --- a/projects/project2/project2.c +++ b/projects/project2/project2.c @@ -228,7 +228,7 @@ struct TaskNamePair_t { TaskHandle_t value; } ; -static struct TaskNamePair_t TaskNamePairs[7]; +static struct TaskNamePair_t TaskNamePairs[8]; void vGetTaskHandle( char *key, TaskHandle_t *t) { @@ -266,6 +266,13 @@ struct MonitorTaskArgs_t fpga_args = { .smbus_status = &eStatus6, }; +// Supply Address | Voltages | Priority +// ---------------+----------|----------- +// 0x40 | 3.3 & 1.8| 2 +// 0x44 | KVCCINT | 1 +// 0x43 | KVCCINT | 1 +// 0x46 | VVCCINT | 1 +// 0x45 | VVCCINT | 1 struct dev_i2c_addr_t pm_addrs_dcdc[] = { {"3V3/1V8", 0x70, 0, 0x40}, {"KVCCINT1", 0x70, 1, 0x44}, @@ -318,6 +325,12 @@ int main( void ) cli_uart1.uart_base = UART1_BASE; cli_uart1.UartStreamBuffer = xUART1StreamBuffer; cli_uart4.uart_base = UART4_BASE; cli_uart4.UartStreamBuffer = xUART4StreamBuffer; + // clear the various buffers + for (int i =0; i < dcdc_args.n_values; ++i) + dcdc_args.pm_values[i] = -999.; + for (int i =0; i < fpga_args.n_values; ++i) + fpga_args.pm_values[i] = -999.; + // start the tasks here xTaskCreate(PowerSupplyTask, "POW", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+5, &TaskNamePairs[0].value); xTaskCreate(LedTask, "LED", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+2, &TaskNamePairs[1].value); @@ -327,6 +340,7 @@ int main( void ) xTaskCreate(FireFlyTask, "FFLY", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+4, &TaskNamePairs[6].value); xTaskCreate(MonitorTask, "PSMON", configMINIMAL_STACK_SIZE, &dcdc_args, tskIDLE_PRIORITY+4, &TaskNamePairs[5].value); xTaskCreate(MonitorTask, "XIMON", configMINIMAL_STACK_SIZE, &fpga_args, tskIDLE_PRIORITY+4, &TaskNamePairs[7].value); + xTaskCreate(AlarmTask, "ALARM", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY+5, &TaskNamePairs[8].value); snprintf(TaskNamePairs[0].key,configMAX_TASK_NAME_LEN,"POW"); snprintf(TaskNamePairs[1].key,configMAX_TASK_NAME_LEN,"LED"); @@ -336,7 +350,10 @@ int main( void ) snprintf(TaskNamePairs[5].key,configMAX_TASK_NAME_LEN,"PSMON"); snprintf(TaskNamePairs[6].key,configMAX_TASK_NAME_LEN,"FFLY"); snprintf(TaskNamePairs[7].key,configMAX_TASK_NAME_LEN,"XIMON"); + snprintf(TaskNamePairs[8].key,configMAX_TASK_NAME_LEN,"ALARM"); + // ------------------------------------------------- + // Initialize all the queues // queue for the LED xLedQueue = xQueueCreate(5, // The maximum number of items the queue can hold. sizeof( uint32_t )); // The size of each item. @@ -346,17 +363,25 @@ int main( void ) configASSERT(xPwrQueue != NULL); + xAlmQueue = xQueueCreate(10, sizeof(uint32_t)); // ALARM queue + configASSERT(xAlmQueue != NULL); + +#ifdef DEBUGxx vQueueAddToRegistry(xLedQueue, "LedQueue"); vQueueAddToRegistry(xPwrQueue, "PwrQueue"); +#endif // DEBUG - // Set up the hardware ready to run the demo. Don't do this earlier as the interrupts - // call some FreeRTOS tasks that need to be set up first. + // Set up the hardware ready to run the firmware. Don't do this earlier as + // the interrupts call some FreeRTOS tasks that need to be set up first. SystemInit(); - Print("\n\r----------------------------\n\r"); - Print("Staring Project2 " FIRMWARE_VERSION " (FreeRTOS scheduler about to start)\n\r"); - Print("Built on " __TIME__", " __DATE__ "\n\r"); - Print( "----------------------------\n\r"); + // Say hello. The information below is only updated when the main() + // function is recompiled. + Print("\r\n----------------------------\r\n"); + Print("Staring Apollo CM MCU firmware " FIRMWARE_VERSION + "\r\n\t\t (FreeRTOS scheduler about to start)\r\n"); + Print("Built on " __TIME__", " __DATE__ "\r\n"); + Print( "----------------------------\r\n"); // start the scheduler -- this function should not return vTaskStartScheduler();