yasimavr

Contents:

  • Command Line Usage
  • Key Concepts
  • Developer Reference
  • Examples
    • LED Blink (ATMega328)
      • Firmware source
      • Simulation script
  • IDE Integration
yasimavr
  • Examples
  • LED Blink (ATMega328)
  • View page source

LED Blink (ATMega328)

This example illustrates the classic “ATMega328 running a firmware to blink a LED” example. It is composed of two files:

  • mega328_blink_fw.c : source code for the firmware to run inside the model

  • mega328_blink.py : simulation script

The Firmware uses the GPIO pin PB0 as output to drive a (virtual) LED.

It uses the Timer1 configured in CTC mode to trigger overflow interrupts at a 0.5Hz frequency. On each interrupt, the pin PB0 output state is toggled, thus giving it a 1 Hz period, 50% duty cycle.

The simulation script reads the firmware binary file and loads it into a ATMega328 model. It connects a SignalHook that simply prints out the state of the LED whenever it changes. Finally, it runs the simulation for 10 secs of simulated time.

Firmware source

mega328_blink.fw.c:

#define F_CPU 1000000

#include <avr/io.h>
#include <avr/interrupt.h>


/****************************************/

ISR(TIMER1_COMPA_vect)
{
    //Toggle pin PB0
    PORTB ^= 0x01;
}

void main() {
    //Port config, PB0 as output, initially low
    DDRB = 0x01;
    PORTB = 0x00;

    //Timer1 configuration

    //The counter period threshold is set to 0.5s
    OCR1A = F_CPU / 1024 / 2;
    //Timer1 enabled, configured in CTC mode with 1024 prescaling factor
    TCCR1B = _BV(WGM12) | _BV(CS12) | _BV(CS10);
    //Enable the interrupt vector for Timer1 output compare A
    TIMSK1 = _BV(OCIE1A);

    //Infinite loop
    sei();
    while(1);
}

Simulation script

mega328_blink.py:

import os
from yasimavr.device_library import load_device
from yasimavr.lib import core as corelib


#This function implements a hook that will be called by the pin signal.
#It captures digital state change notifications and prints the new LED state.
def pin_hook(sigdata, hooktag):
    #Filter the notifications, we're only interested in digital state changes
    if sigdata.sigid == corelib.Wire.SignalId.DigitalChange:
        #Obtain the new pin state
        pin_state = sigdata.data.as_uint()
        led_state = 'ON' if pin_state else 'OFF'
        #Print the state
        print('LED state:', led_state)


def main():

    #Uncomment this to have the global trace and logging
    #corelib.global_logger().set_level(corelib.Logger.Level.Trace)

    #Create a new MCU model ATMega328
    device = load_device('atmega328')

    #Uncomment this to have the device trace and logging
    #device.logger().set_level(corelib.Logger.Level.Trace)
    #device.find_peripheral('TC_1').logger().set_level(corelib.Logger.Level.Trace)

    #Create a simulation loop for this device
    simloop = corelib.SimLoop(device)

    #Load the firmware with a MCU clock of 1MHz
    fw_path = os.path.join(os.path.dirname(__file__), 'mega328_blink_fw.elf')
    firmware = corelib.Firmware.read_elf(fw_path)
    firmware.frequency = 1000000
    device.load_firmware(firmware)

    #Find the pin driving the LED and connect a hook to its signal
    pin = device.find_pin('PB0')
    hook = corelib.CallableSignalHook(pin_hook)
    pin.signal().connect(hook)

    #Run the simulation for 10 million cycles (representing 10 secs of simulated time).
    #Because the fast simulation mode is disabled, this should be roughly 10 secs of
    #real world time as well.
    simloop.run(10000000)


if __name__ == '__main__':
    main()

Note

The script assumes that the user has compiled the firmware code into a ELF file named mega328_blink_fw.elf in the same directory.

Previous Next

© Copyright 2023-2024, C.Savergne.

Built with Sphinx using a theme provided by Read the Docs.