diff --git a/CHANGELOG.md b/CHANGELOG.md index f3ed5171..d22c03bc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ This document summarizes the changes introduced to the code base for each release. +## v1.0.4 + +- Fix injection period inconsistencies +- Add ramp injection function +- Add AMDS driver counter access API +- Add top priority scheduler task register method + ## v1.0.3 - Fix bug in Vivado project vs. C code config checking diff --git a/sdk/app_cpu1/common/drv/motherboard.c b/sdk/app_cpu1/common/drv/motherboard.c index c0d7b05c..17e07f2b 100644 --- a/sdk/app_cpu1/common/drv/motherboard.c +++ b/sdk/app_cpu1/common/drv/motherboard.c @@ -98,4 +98,25 @@ void motherboard_print_counters(uint32_t base_addr) cmd_resp_printf("T: %08X\r\n", m_motherboard[MOTHERBOARD_DEFS_OFFSET_COUNT_TIMEOUT / 4]); } +void motherboard_get_counters(uint32_t base_addr, uint32_t *V, uint32_t *C, uint32_t *T) +{ + // Create base address for IP + volatile uint32_t *m_motherboard = (volatile uint32_t *) base_addr; + + // Read V counter if user requested it + if (V != NULL) { + *V = m_motherboard[MOTHERBOARD_DEFS_OFFSET_COUNT_VALID / 4]; + } + + // Read C counter if user requested it + if (C != NULL) { + *C = m_motherboard[MOTHERBOARD_DEFS_OFFSET_COUNT_CORRUPT / 4]; + } + + // Read T counter if user requested it + if (T != NULL) { + *T = m_motherboard[MOTHERBOARD_DEFS_OFFSET_COUNT_TIMEOUT / 4]; + } +} + #endif // USER_CONFIG_ENABLE_MOTHERBOARD_SUPPORT diff --git a/sdk/app_cpu1/common/drv/motherboard.h b/sdk/app_cpu1/common/drv/motherboard.h index b710cc66..8e642ddb 100644 --- a/sdk/app_cpu1/common/drv/motherboard.h +++ b/sdk/app_cpu1/common/drv/motherboard.h @@ -83,5 +83,6 @@ int motherboard_get_data(uint32_t base_addr, mb_channel_e channel, int32_t *out) void motherboard_print_samples(uint32_t base_addr); void motherboard_print_counters(uint32_t base_addr); +void motherboard_get_counters(uint32_t base_addr, uint32_t *V, uint32_t *C, uint32_t *T); #endif // MOTHERBOARD_H diff --git a/sdk/app_cpu1/common/sys/cmd/cmd_inj.c b/sdk/app_cpu1/common/sys/cmd/cmd_inj.c index 8bf941ad..bca0e467 100644 --- a/sdk/app_cpu1/common/sys/cmd/cmd_inj.c +++ b/sdk/app_cpu1/common/sys/cmd/cmd_inj.c @@ -221,6 +221,37 @@ int cmd_inj(int argc, char **argv) return CMD_SUCCESS; } + // Handle 'inj ramp ...' command + if (argc == 7 && STREQ("ramp", argv[1])) { + // Parse out name and convert to injection context + inj_ctx_t *ctx = injection_find_ctx_by_name(argv[2]); + if (ctx == NULL) { + return CMD_INVALID_ARGUMENTS; + } + + // Parse out operation + inj_op_e op; + if (_parse_op(argv[3], &op) != 0) { + return CMD_INVALID_ARGUMENTS; + } + + // Pull out valueMin argument + double valueMin = strtod(argv[4], NULL); + + // Pull out valueMax argument + double valueMax = strtod(argv[5], NULL); + + // Pull out period argument + double period = strtod(argv[6], NULL); + if (period < 0.0) { + return CMD_INVALID_ARGUMENTS; + } + + injection_ramp(ctx, op, valueMin, valueMax, period); + + return CMD_SUCCESS; + } + return CMD_INVALID_ARGUMENTS; } diff --git a/sdk/app_cpu1/common/sys/injection.c b/sdk/app_cpu1/common/sys/injection.c index 317501b9..95e0cf7b 100644 --- a/sdk/app_cpu1/common/sys/injection.c +++ b/sdk/app_cpu1/common/sys/injection.c @@ -110,6 +110,18 @@ static inline double _square(double min, double max, double period, double time) return out; } +static inline double _ramp(double min, double max, double period, double time) +{ + double out; + // Calculate slope + double m_pos = (max - min) / (period); + + // Calculate output + out = m_pos * time + min; + + return out; +} + void injection_init(void) { cmd_inj_register(); @@ -221,7 +233,7 @@ void injection_inj(double *output, inj_ctx_t *ctx, double Ts) { ctx->curr_time += Ts; if (ctx->curr_time >= ctx->chirp.period) { - ctx->curr_time = 0.0; + ctx->curr_time -= ctx->chirp.period; } value = _chirp( @@ -233,7 +245,7 @@ void injection_inj(double *output, inj_ctx_t *ctx, double Ts) { ctx->curr_time += Ts; if (ctx->curr_time >= ctx->triangle.period) { - ctx->curr_time = 0.0; + ctx->curr_time -= ctx->triangle.period; } value = _triangle(ctx->triangle.valueMin, ctx->triangle.valueMax, ctx->triangle.period, ctx->curr_time); @@ -244,13 +256,24 @@ void injection_inj(double *output, inj_ctx_t *ctx, double Ts) { ctx->curr_time += Ts; if (ctx->curr_time >= ctx->square.period) { - ctx->curr_time = 0.0; + ctx->curr_time -= ctx->square.period; } value = _square(ctx->square.valueMin, ctx->square.valueMax, ctx->square.period, ctx->curr_time); break; } + case RAMP: + { + ctx->curr_time += Ts; + if (ctx->curr_time >= ctx->ramp.period) { + ctx->curr_time -= ctx->ramp.period; + } + + value = _ramp(ctx->ramp.valueMin, ctx->ramp.valueMax, ctx->ramp.period, ctx->curr_time); + break; + } + case NONE: default: // Injection function not set by user, @@ -357,6 +380,16 @@ void injection_square(inj_ctx_t *ctx, inj_op_e op, double valueMin, double value ctx->square.period = period; } +void injection_ramp(inj_ctx_t *ctx, inj_op_e op, double valueMin, double valueMax, double period) +{ + ctx->inj_func = RAMP; + ctx->operation = op; + ctx->curr_time = 0.0; + ctx->ramp.valueMin = valueMin; + ctx->ramp.valueMax = valueMax; + ctx->ramp.period = period; +} + // *************************** // Code for running the state machine to // list the registered injection contexts diff --git a/sdk/app_cpu1/common/sys/injection.h b/sdk/app_cpu1/common/sys/injection.h index 3f06669f..532a98ea 100644 --- a/sdk/app_cpu1/common/sys/injection.h +++ b/sdk/app_cpu1/common/sys/injection.h @@ -9,6 +9,7 @@ typedef enum inj_func_e { CHIRP, TRIANGLE, SQUARE, + RAMP, NONE, } inj_func_e; @@ -46,6 +47,12 @@ typedef struct inj_func_square_t { double period; } inj_func_square_t; +typedef struct inj_func_ramp_t { + double valueMin; + double valueMax; + double period; +} inj_func_ramp_t; + #define INJ_MAX_NAME_LENGTH (24) typedef struct inj_ctx_t { @@ -62,6 +69,7 @@ typedef struct inj_ctx_t { inj_func_chirp_t chirp; inj_func_triangle_t triangle; inj_func_square_t square; + inj_func_ramp_t ramp; double curr_time; } inj_ctx_t; @@ -82,6 +90,7 @@ void injection_noise(inj_ctx_t *ctx, inj_op_e op, double gain, double offset); void injection_chirp(inj_ctx_t *ctx, inj_op_e op, double gain, double freqMin, double freqMax, double period); void injection_triangle(inj_ctx_t *ctx, inj_op_e op, double valueMin, double valueMax, double period); void injection_square(inj_ctx_t *ctx, inj_op_e op, double valueMin, double valueMax, double period); +void injection_ramp(inj_ctx_t *ctx, inj_op_e op, double valueMin, double valueMax, double period); inj_ctx_t *injection_find_ctx_by_name(char *name); diff --git a/sdk/app_cpu1/common/sys/scheduler.c b/sdk/app_cpu1/common/sys/scheduler.c index 5f8bde3e..c0a402dc 100644 --- a/sdk/app_cpu1/common/sys/scheduler.c +++ b/sdk/app_cpu1/common/sys/scheduler.c @@ -30,17 +30,25 @@ void scheduler_timer_isr(void *arg) // We should be done running tasks in a time slice before this fires, // so if tasks are still running, we consumed too many cycles per slice if (tasks_running) { - // Use raw printf so this goes directly to the UART device - xil_printf("ERROR: OVERRUN SCHEDULER TIME QUANTUM!\n"); - - led_set_color(0, LED_COLOR_RED); - led_set_color(1, LED_COLOR_RED); - led_set_color(2, LED_COLOR_RED); - led_set_color(3, LED_COLOR_RED); - - // Hang here so the user can debug why the code took so long - // and overran the time slice! See the `running_task` variable. - while (1) { + // Per AMDC-Firmware Issue #265, during start-up, the overrun check + // seems to falsely trigger, or at least, we do not care about the trigger. + // + // To fix this, wait until at least 100 time slices have elapsed + // before allowing it to trigger. + if (elapsed_usec > 100 * SYS_TICK_USEC) { + // Use raw printf so this goes directly to the UART device + xil_printf("ERROR: OVERRUN SCHEDULER TIME QUANTUM!\r\n"); + xil_printf("ERROR: CURRENT TASK IS %s\n", running_task->name); + + led_set_color(0, LED_COLOR_RED); + led_set_color(1, LED_COLOR_RED); + led_set_color(2, LED_COLOR_RED); + led_set_color(3, LED_COLOR_RED); + + // Hang here so the user can debug why the code took so long + // and overran the time slice! See the `running_task` variable. + while (1) { + } } } #endif // USER_CONFIG_ENABLE_TIME_QUANTUM_CHECKING @@ -109,6 +117,29 @@ int scheduler_tcb_register(task_control_block_t *tcb) return SUCCESS; } +int scheduler_tcb_register_high_priority(task_control_block_t *tcb) +{ + // Don't let clients re-register their tcb + if (tcb->is_registered) { + return FAILURE; + } + + // Mark as registered + tcb->is_registered = true; + + if (tasks == NULL) { + // There are no tasks in linked list + tasks = tcb; + tasks->next = NULL; + } else { + // Put new tcb at front of linked list + tcb->next = tasks; + tasks = tcb; + } + + return SUCCESS; +} + int scheduler_tcb_unregister(task_control_block_t *tcb) { // Don't let clients unregister their already unregistered tcb diff --git a/sdk/app_cpu1/common/sys/scheduler.h b/sdk/app_cpu1/common/sys/scheduler.h index 7532a0e2..5ec81337 100644 --- a/sdk/app_cpu1/common/sys/scheduler.h +++ b/sdk/app_cpu1/common/sys/scheduler.h @@ -49,6 +49,7 @@ void scheduler_run(void); void scheduler_tcb_init( task_control_block_t *tcb, task_callback_t callback, void *callback_arg, const char *name, uint32_t interval_usec); int scheduler_tcb_register(task_control_block_t *tcb); +int scheduler_tcb_register_high_priority(task_control_block_t *tcb); int scheduler_tcb_unregister(task_control_block_t *tcb); bool scheduler_tcb_is_registered(task_control_block_t *tcb);