Yet another Atom Arduino blinker
While experimenting with Atom I produced a minimal example for making my old Arduino Uno blink its LED periodically.
Although there are plenty of examples out there (some of them even work!) I didn’t want to introduce any dependency to the Arduino libraries. Besides making it harder to build (even if arscons is quite nice) it increases the object size and Arduino only supports a limited range of processors. I need the flexibility to use the code on controlles like the ATTiny45
Most examples are uncommented and therefore hard to understand for beginners. Although I think Atom is conceptually significantly easier to understand than Copilot the classical embedded C programmer might require commented source code in order to fully understand Atom.
Additionally, I use the technique described in the QuasiQutation post in order to increase the readability of the inlined C code. Additionally, I disabled features like assertions and rule coverage
{-# LANGUAGE QuasiQuotes #-}
{-|
Minimalistic Atom reset example for ATMega328P.
The LED is assumed to be on PB5 (e.g. Arduino Uno).
No Arduino Libraries are required.
Compilation example:
@
runghc Blink.hs
avr-gcc -o Blink.elf -Os -Wall -mmcu=atmega328p -DF_CPU=16000000L blink.c
avr-objcopy -O ihex -R .eeprom Blink.elf Blink.hex
@
-}
module Blink (main) where
import StringEmbed
import Language.Atom
-- | Our main Atom program.
-- Periodically blinks the LED
blink :: Atom ()
blink = do
-- Declare a local state variable
-- that controls if the LED is on or off
on <- bool "on" True
-- Every 50000'th call of blink() ...
period 50000 $ atom "blinkOn" $ do
-- invert LED state
on <== not_ (value on)
-- and write the new state to PORTB
call "showLED"
-- | C code that will be inserted BEFORE the atom code
cHeader :: String
cHeader = [embedStr|
#include <avr/io.h>
#include <util/delay.h>
static inline void showLED(void);
|]
-- | C code that will be inserted AFTER the atom code
cFooter :: String
cFooter = [embedStr|
//LED: PB5
#define LED_PIN (1<<5)
//Set/reset the LED
static inline void showLED() {
if(state.blink.on) {
PORTB |= LED_PIN;
} else {
PORTB &= ~(LED_PIN);
}
}
int main (void) {
//Set LED pin to OUTPUT
DDRB |= LED_PIN;
while(1) {
blink();
}
return 0; //Never reache
}
|]
main :: IO ()
main = do
let code _ _ _ = (cHeader, cFooter)
let cfg = defaults {cCode = code,
cRuleCoverage = False,
cAssert = False}
(schedule, _, _, _, _) <- compile "blink" cfg blink
putStrLn $ reportSchedule schedule