diff --git a/common/power_ctl.c b/common/power_ctl.c index 3cc32eba..05ee4cdb 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}, @@ -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/ADCMonitorTask.c b/projects/project2/ADCMonitorTask.c index f83c5a8c..c6427551 100644 --- a/projects/project2/ADCMonitorTask.c +++ b/projects/project2/ADCMonitorTask.c @@ -32,17 +32,13 @@ #include "driverlib/rom.h" #include "driverlib/adc.h" -// FreeRTOS -#include "FreeRTOS.h" -#include "FreeRTOSConfig.h" -#include "task.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 { @@ -108,59 +104,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/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 d4efec94..24654d6f 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 @@ -51,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 @@ -183,7 +180,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 +293,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 +322,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; @@ -360,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) @@ -421,8 +478,6 @@ static BaseType_t led_ctl(char *m, size_t s, const char *mm) return pdFALSE; } - - // dump monitor information static BaseType_t mon_ctl(char *m, size_t s, const char *mm) { @@ -432,18 +487,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 +513,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) @@ -483,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) @@ -495,7 +546,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 +568,91 @@ static BaseType_t ff_ctl(char *m, size_t s, const char *mm) return pdFALSE; } +// 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. +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 ) @@ -705,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", @@ -752,6 +897,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 +923,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,12 +941,14 @@ 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); + 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 @@ -794,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/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 e5815fd2..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 @@ -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< +#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..e0dae866 100644 --- a/projects/project2/Makefile +++ b/projects/project2/Makefile @@ -90,7 +90,9 @@ ${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 ## FreeRTOS ${COMPILER}/project2.axf: ${COMPILER}/tasks.o @@ -109,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 7323e327..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 @@ -38,78 +44,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; - -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; - -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]; - } -} -// Monitor temperatures, voltages, currents, via I2C/PMBUS void MonitorTask(void *parameters) { // initialize to the current tick time 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; - } - - //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}; + struct MonitorTaskArgs_t *args = parameters; + + + //vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 2500 ) ); + 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 ) { @@ -122,37 +79,39 @@ 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; } @@ -160,52 +119,54 @@ 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; @@ -213,7 +174,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; @@ -221,20 +182,20 @@ 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(); vTaskDelayUntil( &xLastWakeTime, pdMS_TO_TICKS( 250 ) ); } // infinite loop diff --git a/projects/project2/MonitorTask.h b/projects/project2/MonitorTask.h index e9783fd4..4008c194 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; @@ -23,11 +25,34 @@ struct pm_list { int type; }; +// how to find an I2C device, with a mux infront of it. +struct dev_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<(b)?(a):(b) + + +// 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. + +// --- Power Supply management task +void PowerSupplyTask(void *parameters); +extern QueueHandle_t xPwrQueue; + +// --- Semi-generic PMBUS based I2C task +void MonitorTask(void *parameters); + +// --- 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 +void ADCMonitorTask(void *parameters); + +#endif /* PROJECTS_PROJECT2_TASKS_H_ */ diff --git a/projects/project2/project2.c b/projects/project2/project2.c index 40862998..44c3f053 100644 --- a/projects/project2/project2.c +++ b/projects/project2/project2.c @@ -25,6 +25,9 @@ #include "common/pinsel.h" #include "common/smbus.h" #include "CommandLineTask.h" +#include "InterruptHandlers.h" +#include "MonitorTask.h" +#include "Tasks.h" // TI Includes #include "inc/hw_types.h" @@ -92,171 +95,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 ); -} - - @@ -377,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() { @@ -410,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) { @@ -422,8 +240,72 @@ 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, +}; + +// 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}, + {"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 ) @@ -443,23 +325,35 @@ 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); - 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); + 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"); - 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"); + 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. @@ -469,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 at " __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(); 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