LED display code

First post : 23 August 2018

Simple cpu LED code

Here is some simple LED firmware, that provides the basic framework for a cpu led. The LED flashes every second and allows for a start-up display as described in the previous tutorial.

The basics of the operation is a millisecond down counter. If the counter is above 0, the LED is on. It is initially loaded with 1000, and then loaded with 50, every second. Additional LEDs can be controlled in the same manner, this again allows for a start-up globe test, and provides an interface which the firmware can use to easily flash, on just drive the LEDs.

// the timer interrupt interface variables
// these need to be volatile as to interconnect a main routine and an interrupt
struct MS_int_t{
      volatile uint32_t       Lock; // a flag
      volatile uint32_t       ms_passed;
}       Ms_int;

// led on timers.
uint32_t       CPU_led_on_ms;

static struct timer_task TIMER_0_task1; // use to initialize the timer

// this is the timer 1ms interrupt
static void TIMER_0_task_ms_cb(const struct timer_task *const timer_task)
      static uint32_t       ms_internal_cnt = 0; // the local count is needed in case the lock flag is set.

      if (Ms_int.Lock == 0){
            Ms_int.ms_passed += ms_internal_cnt; // this is in case a previous interrupt occurred while the lock flag was set
            ms_internal_cnt = 0;

// the interface to the init code provided by atmel start
void TIMER_0_setup(void)
      TIMER_0_task1.interval = 1;
      TIMER_0_task1.cb          = TIMER_0_task_ms_cb;
      TIMER_0_task1.mode       = TIMER_TASK_REPEAT;
      timer_add_task(&TIMER_0, &TIMER_0_task1);       // init code provided by the atmel start generated code
      timer_start(&TIMER_0);                                     // init code provided by the atmel start generated code

// this function returns the amount of millisecond that has passed since it was last called
// this function should ideally only be called by the housekeeping routine
uint32_t       get_ms_passed(void){
uint32_t       ms_passed;
      Ms_int.Lock = 1;
      ms_passed = Ms_int.ms_passed;
      Ms_int.ms_passed = 0;
      Ms_int.Lock = 0;
      return ms_passed;

// this function includes everything that happens in the background,
// eg led flashing, timers, comms routines ADC scanning schedules etc
// this function returns the amount of millisecond that has passed since it was last called

uint32_t housekeeping(void){
uint32_t             ms_passed;
static uint32_t             second_timer = 0;

      ms_passed = get_ms_passed();
      if (CPU_led_on_ms > ms_passed)             CPU_led_on_ms -= ms_passed;             else       CPU_led_on_ms = 0;
      if (CPU_led_on_ms)             gpio_set_pin_level(cpu_led,true);             else       gpio_set_pin_level(cpu_led,false);

      second_timer += ms_passed;
      if (second_timer > 1000)
            second_timer -= 1000;
            if (CPU_led_on_ms < 50)
                  CPU_led_on_ms = 50;

int main(void)
      uint32_t       ms_passed = 0;

      atmel_start_init(); // init code provided by the atmel start generated code

// init of the interrupt interface
      Ms_int.Lock = 1;
      Ms_int.ms_passed = 0;
      Ms_int.Lock = 0;

// the initial long on value of the cpu led is there to differentiate between startup and running. Otherwise a periodic restart may be confused for a normally running system.
      CPU_led_on_ms = 1000;
// additional LED are also loaded with the 1 second on period
//       as this provides a "lamp test" function.
//       This lets the user know that the LEDs and drive circuitry does indeed work

      while (1) {
            ms_passed = housekeeping();
            //put your main application code here

Previous... LED indicators using Dark Cockpit philosophy
Next... still to come.
Home mail add