diff --git a/freertos_driverlib_f28377s/FreeRTOSConfig.h b/freertos_driverlib_f28377s/FreeRTOSConfig.h index d6460ae..7469743 100644 --- a/freertos_driverlib_f28377s/FreeRTOSConfig.h +++ b/freertos_driverlib_f28377s/FreeRTOSConfig.h @@ -28,7 +28,7 @@ supported, or if both static and dynamic allocation are supported. /* Constants that describe the hardware and memory usage. */ #define configCPU_CLOCK_HZ ( ( unsigned long ) 200000000 ) #define configMINIMAL_STACK_SIZE ( ( uint16_t ) 128 ) -#define configMAX_TASK_NAME_LEN ( 12 ) +#define configMAX_TASK_NAME_LEN ( 16 ) /* Note heap_5.c is used so this only defines the part of the heap that is in @@ -54,8 +54,8 @@ in main.c. // Constants that define which hook (callback) functions should be used #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 -#define configUSE_MALLOC_FAILED_HOOK 0 -#define configCHECK_FOR_STACK_OVERFLOW 0 +#define configUSE_MALLOC_FAILED_HOOK 1 +#define configCHECK_FOR_STACK_OVERFLOW 2 #define configQUEUE_REGISTRY_SIZE 8 @@ -78,7 +78,7 @@ referenced anyway. #define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 -#define INCLUDE_uxTaskGetStackHighWaterMark 0 +#define INCLUDE_uxTaskGetStackHighWaterMark 1 #define INCLUDE_xTaskGetIdleTaskHandle 1 #define INCLUDE_xTaskGetHandle 1 #define INCLUDE_eTaskGetState 1 diff --git a/freertos_driverlib_f28377s/include/sine_table.h b/freertos_driverlib_f28377s/include/sine_table.h new file mode 100644 index 0000000..e9608c0 --- /dev/null +++ b/freertos_driverlib_f28377s/include/sine_table.h @@ -0,0 +1,10 @@ +#ifndef SINE_TABLE_H +#define SINE_TABLE_H + +#include + +#define SINE_TABLE_LENGTH 100U + +extern const uint16_t sineTable[SINE_TABLE_LENGTH]; + +#endif diff --git a/freertos_driverlib_f28377s/main.c b/freertos_driverlib_f28377s/main.c index 70621ad..d8cfdfe 100644 --- a/freertos_driverlib_f28377s/main.c +++ b/freertos_driverlib_f28377s/main.c @@ -3,6 +3,7 @@ #include #include #include +#include #include // Driverlib headers @@ -13,6 +14,7 @@ // Customized headers #include "uart_drv.h" #include "at24cm02.h" +#include "sine_table.h" // FreeRTOS headers #include "FreeRTOS.h" @@ -46,6 +48,18 @@ uint8_t ucHeap[configTOTAL_HEAP_SIZE]; #define SCI_RXDA_PIN 85U #define SCI_TXDA_PIN 84U +#define EPWM6A_GPIO 10U +#define EPWM6A_FREQUENCY_HZ 50000UL // 50KHz +#define EPWM6A_DUTY_PERCENT 75U // 75% +#define EPWM_CLOCK_HZ (DEVICE_SYSCLK_FREQ / 2UL) +#define EPWM6A_PERIOD_COUNTS (EPWM_CLOCK_HZ / EPWM6A_FREQUENCY_HZ) +#define EPWM6A_PERIOD_TICKS (EPWM6A_PERIOD_COUNTS - 1UL) +#define EPWM6A_COMPARE_TICKS ((EPWM6A_PERIOD_COUNTS * EPWM6A_DUTY_PERCENT) / 100UL) + +#define DAC_SINE_FREQUENCY_HZ 1000UL +#define DAC_SAMPLE_FREQUENCY_HZ (DAC_SINE_FREQUENCY_HZ * SINE_TABLE_LENGTH) +#define DAC_SAMPLE_PERIOD_TICKS ((EPWM_CLOCK_HZ / DAC_SAMPLE_FREQUENCY_HZ) - 1UL) + // UART: SCIA void UartSetup(void); void UartPutChar(uint16_t charToWrite); @@ -54,12 +68,23 @@ void UartPutChar(uint16_t charToWrite); void configCPUTimer(uint32_t cpuTimer, uint32_t period_us); __interrupt void timer1_ISR(void); +// ePWM6A: GPIO10, 50KHz, 75% duty cycle +void initEPWM6A(void); + +// DACOUTB sine output and ePWM7 supplies the sample interrupt +void initDACBSine(void); +__interrupt void dacUpdateISR(void); +static volatile uint16_t sineTableIndex = 0U; + // EEPROM: AT24CM02 (2Mbit) static EEPROM_Status eepromInitStatus = EEPROM_STATUS_NOT_INITIALIZED; static uint16_t eepromReadData[AT24CM02_PAGE_SIZE_BYTES]; static uint16_t eepromWriteData[AT24CM02_PAGE_SIZE_BYTES]; -// FreeRTOS tasks +// FreeRTOS +const char * volatile g_overflow_task_name = NULL; +TaskHandle_t volatile g_overflow_task_handle = NULL; + void RedLED_Task(void *pvParameters); void BlueLED_Task(void *pvParameters); void EEPROM_Task(void *pvParameters); @@ -86,9 +111,6 @@ void main(void) { GPIO_setDirectionMode(LED_B, GPIO_DIR_MODE_OUT); GPIO_writePin(LED_B, 0); - // GPIO91/GPIO92 and I2CA are configured by the EEPROM driver. - eepromInitStatus = EEPROM_init(); - // ------------------------------------------------------------------------ // Clear all interrupts and initialize PIE vector table @@ -124,8 +146,9 @@ void main(void) { ERTM; // Enable Global real-time interrupt DBGM - // ------------------------ Redirect STDOUT to SCI ------------------------ + // ------------------------------------------------------------------------ + // SCIA: GPIO84/GPIO85 // Add the UART device. When fopen is called with a filename that // begins "uart:", the UART device will be used to handle the file add_device("uart", _SSA, UART_open, UART_close, UART_read, UART_write, @@ -134,11 +157,21 @@ void main(void) { // Assign stdout to be a UART device assert(freopen("uart:", "w", stdout) != NULL); + // GPIO91/GPIO92 and I2CA are configured by the EEPROM driver + eepromInitStatus = EEPROM_init(); + + // GPIO10 outputs ePWM6A at 50KHz with a 75% duty cycle + initEPWM6A(); + + // Generate a 1 kHz sine wave on DACOUTB + initDACBSine(); + // ------------------------------- FreeRTOS ------------------------------- xSemaphore = xSemaphoreCreateBinary(); - // Create tasks dynamically + // 1 stack element = 1 * uint16_t = 16 bits = 2 conventional bytes + // 256 stack elements * 2 bytes = 512 conventional bytes xTaskCreate(RedLED_Task, (const char*) "RedLED_Task", 256, @@ -168,12 +201,16 @@ void main(void) { void RedLED_Task(void *pvParameters) { (void)pvParameters; int uart_count = 0; + UBaseType_t uxRemainingWords; while (1) { if (xSemaphoreTake(xSemaphore, portMAX_DELAY) == pdTRUE) { GPIO_togglePin(LED_R); uart_count++; - printf("Hello from FreeRTOS running on the F28377S Coreboard, %d!\r\n", - uart_count); + printf("FreeRTOS running on the F28377S Coreboard V1.3, %d!\r\n", uart_count); + uxRemainingWords = uxTaskGetStackHighWaterMark(NULL); + printf("RedLED_Task unused stack: %d stack elements (%d bytes)\r\n", + (int)uxRemainingWords, + (int)(uxRemainingWords * sizeof(StackType_t) * (CHAR_BIT / 8U))); } } } @@ -240,6 +277,110 @@ void EEPROM_Task(void *pvParameters) { vTaskDelete(NULL); } +void vApplicationStackOverflowHook(TaskHandle_t xTask, char *pcTaskName) { + g_overflow_task_handle = xTask; + g_overflow_task_name = pcTaskName; // points to the task name string + taskDISABLE_INTERRUPTS(); + for (;;) { + __asm(" NOP"); // set breakpoint here and inspect g_overflow_task_name + } +} + +void vApplicationMallocFailedHook(void) { + taskDISABLE_INTERRUPTS(); + for(;;){} +} + +// ----------------------------------------------------------------------------------------- + +void initEPWM6A(void) { + // Route ePWM6A to GPIO10 + GPIO_setMasterCore(EPWM6A_GPIO, GPIO_CORE_CPU1); + GPIO_setPadConfig(EPWM6A_GPIO, GPIO_PIN_TYPE_STD); + GPIO_setPinConfig(GPIO_10_EPWM6A); + + // The F28377S runs at 200 MHz. Divide EPWMCLK by two so TBCLK is + // 100 MHz, then freeze all ePWM time-base clocks during configuration + SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_2); + SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC); + + EPWM_setClockPrescaler(EPWM6_BASE, + EPWM_CLOCK_DIVIDER_1, + EPWM_HSCLOCK_DIVIDER_1); + EPWM_setTimeBaseCounterMode(EPWM6_BASE, EPWM_COUNTER_MODE_UP); + EPWM_setTimeBasePeriod(EPWM6_BASE, (uint16_t)EPWM6A_PERIOD_TICKS); + EPWM_setTimeBaseCounter(EPWM6_BASE, 0U); + EPWM_disablePhaseShiftLoad(EPWM6_BASE); + EPWM_setPhaseShift(EPWM6_BASE, 0U); + + EPWM_setCounterCompareValue(EPWM6_BASE, + EPWM_COUNTER_COMPARE_A, + (uint16_t)EPWM6A_COMPARE_TICKS); + EPWM_setCounterCompareShadowLoadMode(EPWM6_BASE, + EPWM_COUNTER_COMPARE_A, + EPWM_COMP_LOAD_ON_CNTR_ZERO); + + // Drive ePWM6A high at the start of each period and low at CMPA + EPWM_setActionQualifierAction(EPWM6_BASE, + EPWM_AQ_OUTPUT_A, + EPWM_AQ_OUTPUT_HIGH, + EPWM_AQ_OUTPUT_ON_TIMEBASE_ZERO); + EPWM_setActionQualifierAction(EPWM6_BASE, + EPWM_AQ_OUTPUT_A, + EPWM_AQ_OUTPUT_LOW, + EPWM_AQ_OUTPUT_ON_TIMEBASE_UP_CMPA); + + SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC); +} + +// ----------------------------------------------------------------------------------------- + +void initDACBSine(void) { + // Configure DACOUTB for 12-bit output referenced to ADC VREFHI. + DAC_setReferenceVoltage(DACB_BASE, DAC_REF_ADC_VREFHI); + DAC_setLoadMode(DACB_BASE, DAC_LOAD_SYSCLK); + DAC_setShadowValue(DACB_BASE, sineTable[0U]); + DAC_enableOutput(DACB_BASE); + DEVICE_DELAY_US(10U); + + // Use ePWM7 only as a 100 kHz sample clock. With a 100 MHz TBCLK, + // up-count mode and TBPRD = 999 produce one interrupt every 10 us. + SysCtl_disablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC); + SysCtl_setEPWMClockDivider(SYSCTL_EPWMCLK_DIV_2); + EPWM_setClockPrescaler(EPWM7_BASE, + EPWM_CLOCK_DIVIDER_1, + EPWM_HSCLOCK_DIVIDER_1); + EPWM_setTimeBaseCounterMode(EPWM7_BASE, EPWM_COUNTER_MODE_UP); + EPWM_setTimeBasePeriod(EPWM7_BASE, + (uint16_t)DAC_SAMPLE_PERIOD_TICKS); + EPWM_setTimeBaseCounter(EPWM7_BASE, 0U); + EPWM_disablePhaseShiftLoad(EPWM7_BASE); + EPWM_setPhaseShift(EPWM7_BASE, 0U); + + EPWM_setInterruptSource(EPWM7_BASE, EPWM_INT_TBCTR_ZERO); + EPWM_setInterruptEventCount(EPWM7_BASE, 1U); + EPWM_clearEventTriggerInterruptFlag(EPWM7_BASE); + + Interrupt_register(INT_EPWM7, &dacUpdateISR); + Interrupt_enable(INT_EPWM7); + EPWM_enableInterrupt(EPWM7_BASE); + + sineTableIndex = 1U; + SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_TBCLKSYNC); +} + +__interrupt void dacUpdateISR(void) { + DAC_setShadowValue(DACB_BASE, sineTable[sineTableIndex]); + + sineTableIndex++; + if (sineTableIndex >= SINE_TABLE_LENGTH) { + sineTableIndex = 0U; + } + + EPWM_clearEventTriggerInterruptFlag(EPWM7_BASE); + Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP3); +} + // ----------------------------------------------------------------------------------------- // This function initializes the selected timer to the period specified diff --git a/freertos_driverlib_f28377s/source/sine_table.c b/freertos_driverlib_f28377s/source/sine_table.c new file mode 100644 index 0000000..7b48849 --- /dev/null +++ b/freertos_driverlib_f28377s/source/sine_table.c @@ -0,0 +1,17 @@ +#include "sine_table.h" + +// One complete sine-wave cycle for the F28377S 12-bit buffered DAC. +// The waveform is centered at mid-scale (2048) and spans 0 through 4095. +const uint16_t sineTable[SINE_TABLE_LENGTH] = +{ + 2048U, 2176U, 2304U, 2431U, 2557U, 2680U, 2801U, 2919U, 3034U, 3145U, + 3251U, 3353U, 3449U, 3540U, 3625U, 3704U, 3776U, 3842U, 3900U, 3951U, + 3995U, 4031U, 4059U, 4079U, 4091U, 4095U, 4091U, 4079U, 4059U, 4031U, + 3995U, 3951U, 3900U, 3842U, 3776U, 3704U, 3625U, 3540U, 3449U, 3353U, + 3251U, 3145U, 3034U, 2919U, 2801U, 2680U, 2557U, 2431U, 2304U, 2176U, + 2048U, 1919U, 1791U, 1664U, 1538U, 1415U, 1294U, 1176U, 1061U, 950U, + 844U, 742U, 646U, 555U, 470U, 391U, 319U, 253U, 195U, 144U, + 100U, 64U, 36U, 16U, 4U, 0U, 4U, 16U, 36U, 64U, + 100U, 144U, 195U, 253U, 319U, 391U, 470U, 555U, 646U, 742U, + 844U, 950U, 1061U, 1176U, 1294U, 1415U, 1538U, 1664U, 1791U, 1919U +};