Monday, October 21, 2013

Yakindu Statechart Tools Arduino Integration

This blog has been moved: http://scholtyssek.org/blog/2013/10/21/yakindu-statechart-tools-arduino-integration/

The Yakindu Statechart Tools are predestined to describe behaviour for a system and afterwards generate code. The output code could be Java, C or C++. We would like to use the code generator in the context of embedded systems and so we decided to generate code for an Arduino Uno. Therefor we modified our statechart TrafficLight example and implemented some simple glue code to map the hardware timer and the I/O-ports. Furthermore it was necessary to built a hardware controller that represents the traffic light and so we created a simple controller (it's available as eagle plan in the appendix and could easily be reconstructed). The example is directly implemented for the AVR ATMEGA328P-PU processor (this one is on the Arduino Uno). It is possible to use the Arduino library to integrate this system, but we would like to support the whole AVR family and so it was the better way to use the AVR library directly. With this solution the Yakindu SCT could be used on many AVR based processors.


To explore the example project, you have to go through some steps:

1. Environment

  • Download the eclipse IDE with Yakindu SCT from our download section, or install the Yakindu SCT by using the Eclipse update manager (see: http://statecharts.org/download.html).
  • On Linux, install the AVR  environment:
    sudo apt-get install avrdude binutils-avr gcc-avr avr-libc gdb-avr.
  • Get the Arduino software from http://arduino.cc/en/Main/Software and build the necessary libArduinoCore.a. See http://playground.arduino.cc/Code/Eclipse#Arduino_core_library for detailed description. Now set the include path to the Arduino specific header files and also to the libArduinoCore.a. The libArduinoCore.a should be stored in a folder called "lib" in the project directory. The include path should look like this:

    <install_dir>/arduino-1.0.5/hardware/arduino/variants/mega
    <install_dir>/arduino-1.0.5/hardware/arduino/cores/arduino
  • Open Eclipse and install the SVN Plugin including the SVN Kit via eclipse marketplace. Afterwards import the ArduinoTrafficLight example project from our SVN repository (http://code.google.com/a/eclipselabs.org/p/yakindu/source/checkout). You can find this project in the example folder. After importing the project, you have to check if the include-path is set correct for your system.
  • Build the TrafficLight hardware controller (see circuit layout in the appendix) and connect the ports to the Arduino Uno.
  • As next you have to generate the C++ code by using the TrafficLight.sgen (right click on the file and then generate artifacts). Currently there is an open issue and you have to fix it manually. Open the src-gen/sc_types.h file and change the datatype sc_integer from int32_t to uint32_t. That's all. Next, compile the code. For this, you can use the icon with the small hammer in eclipse.
  • Last but not least you have to flash the compiled program on the processor by activating the AVR-icon.

Now you are able to use the generated code on the Arduino board. Feel free to modify the statechart model and test the behaviour on the hardware platform.

Some explaining words to the example code

There are three things you have to implement as glue code, so that the Arduino works:

2. CycleRunner


The CycleRunner checks periodically for state changes. It uses timer0 to trigger a completion step periodically. An implementation could look like this:

/**
 * The cycleRunner uses timer0 for his cycle-time-calculation (every second)
 */
void CycleRunner::start(void){
 TCCR0B |= (1<<CS02) | (1<<CS00); // prescaler 1024
 TCNT0 = 0; // Startvalue ->1s to overflow
 TIMSK0 |= (1<<TOIE0);
}

void CycleRunner::runCycle(void){
 trafficlight_runCycle(handle);
}
/*
* the cycleRunner is triggered by this timerinterrupt
*/
ISR(TIMER0_OVF_vect) {
 runCycleFlag = 1;
}

3. Timer and TimeEvent


The Timer class is a representation for the hardware timer and it is responsible for initializing the timer and raising TimeEvents. In this example we are using timer1 from the Arduino to implement the reaction trigger timer. A TimeEvent is triggered when e.g. a transition time expired. There are situations where you have to use several parallel running timer thus it was required to store the timeEvents in an array (see events array in Main.cpp). The Timer checks periodically every 10ms for expired time events and raises them if it's necessary.

// Timer ISR that triggers checking for expired time events
ISR(TIMER1_OVF_vect) {
 TCNT1 = 64911; // startvalue for 10ms

 if ((counter++) >= timer->getTimerOverflowCount()) {
  counter = 0;
  timerRaiseEventFlag = 1;
 }
}


void Timer::raiseTimeEvent() {
 for(int i=0;i<TIMER_COUNT;i++){
  if(events[i] == NULL)
   continue;

  if((events[i]->getTimeMs()/10) <= events[i]->getTimerOverflowCount()){
   trafficlight_raiseTimeEvent(sc_handle, events[i]->getEventId());
   events[i]->setTimerOverflowCount(0);
  }

  events[i]->setTimerOverflowCount(events[i]->getTimerOverflowCount() + 1);
 }
}

3. IO port mapping


At the moment it is necessary to map the IO ports by yourself. You have to define the port direction and define a method to change the signals. For example you can map the red traffic light LED like this:

const uint8_t ledPinTrafficRed = DDB5; // the number of the red LED pin
DDRB |= (1 << ledPinTrafficRed);       // set out direction for this port

Now you are able to change the LED signal by using the getter method from the statemachine interface:

setLight(PORTB, ledPinTrafficRed,
trafficlightIfaceTrafficLight_get_red(&handle));

4. Appendix



Yakindu trafficlight statechart

     Traffic light circuit layout

1 comment:

  1. Do you think statecharts could be made easy enough to be used by non-professionals on the arduino ?

    ReplyDelete