diff --git a/test-microbit/Makefile b/test-microbit/Makefile index 99923e2..b8e4e32 100644 --- a/test-microbit/Makefile +++ b/test-microbit/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 2018 Free Software Foundation, Inc. +# Copyright (C) 2018, 2020 Free Software Foundation, Inc. # # This file is part of the Cortex GNAT RTS package. # @@ -16,12 +16,15 @@ # along with this program; see the file COPYING3. If not, see # . -all: seconds.hex testbed.hex +all: circle.hex events.hex seconds.hex -seconds testbed: force - gprbuild -p -P testbed +circle events seconds: rebuild.stamp +rebuild.stamp: force + gprbuild -p -P tests + touch $@ clean:: - gprclean -P testbed + gprclean -P tests + rm -f rebuild.stamp clean:: -rm *~ *.ali *.o *.hex diff --git a/test-microbit/README.md b/test-microbit/README.md new file mode 100644 index 0000000..710b18a --- /dev/null +++ b/test-microbit/README.md @@ -0,0 +1,66 @@ +# micro:bit tests and demos # + +There are three programs built by `make` (or `gprbuild`, but `make` goes on to build hex files that can be dropped onto the micro:bit): + +* `circle` displays a circle running round the LEDs: pressing button A alters the speed, button B alters the direction (clockwise/anticlockwise). The buttons are interrupt-driven. + +* `events` demonstrates `Timing_Events`. The top-left LED (row 1, column 1) flashes every 2 seconds, the LED in row 4, column 5 flashes every 5 seconds. _Why not the bottom right LED? because of the complicated mapping of GPIOs to LEDS_. + +* `seconds` checks out `Clock` functionality by flashing the centre LED once a second. You get to time a number of flashes with a stopwatch to make sure it really is once a second. + +The tests interact with the micro:bit hardware using the [Ada\_Drivers\_Library](https://github.com/AdaCore/Ada_Drivers_Library). Configure it using that library's `project_wizard.py`: +``` +Welcome to the Ada Drivers Library (ADL) project wizard. This script will +ask you some questions to define the ADL configuration of your project. It will +then generate the different files required to use ADL based on this +configuration. +Board + - (0) Custom_Board + - (1) STM32F407_Discovery + - (2) STM32F429_Discovery + - (3) STM32F469_Discovery + - (4) STM32F746_Discovery + - (5) STM32F769_Discovery + - (6) STM32_H405 + - (7) NUCLEO_F446ZE + - (8) Crazyflie + - (9) Feather_STM32F405 + - (10) OpenMV2 + - (11) MicroBit + - (12) NRF52_DK + - (13) HiFive1 + - (14) HiFive1_rev_B + - (15) Unleashed + - (16) Native +? 11 +For key 'Architecture', take value 'ARM' from board definition +For key 'Vendor', take value 'Nordic' from board definition +For key 'Device_Family', take value 'nRF51' from board definition +For key 'Device_Name', take value 'nRF51822xxAA' from board definition +For key 'Number_Of_Interrupts', take value '32' from MCU definition +For key 'Has_ZFP_Runtime', take value 'True' from board definition +For key 'Has_Ravenscar_SFP_Runtime', take value 'False' from board definition +For key 'Has_Ravenscar_Full_Runtime', take value 'False' from board definition +Runtime_Profile + - (0) zfp +? +For key 'Runtime_Name_Suffix', take value 'cortex-m0' from board definition +Runtime_Name [default: 'zfp-cortex-m0'] +? ../../../local/microbit +Use_Startup_Gen [y/N] + +Boot_Memory [default: 'flash'] +? +Max_Path_Length [default: 1024] + +Max_Mount_Points [default: 2] + +Max_Mount_Name_Length [default: 128] + +The configuration is now finished. +Let's generate some files: + -> Writing gprbuild project file. + -> Writing the Ada configuration file. +Your Ada Drivers Library project is now ready to use. +``` +After selecting the `MicroBit`, the default (RET) is OK for most answers. The only odd one is that for `Runtime_Name`; the output files are created in the directory `Ada_Drivers_Library`, so the generated `ada_drivers_library.gpr` is one level down, and to select the locally-installed runtime you have to go up three levels and down 2. diff --git a/test-microbit/buttons.adb b/test-microbit/buttons.adb index d710974..73f8cc8 100644 --- a/test-microbit/buttons.adb +++ b/test-microbit/buttons.adb @@ -1,4 +1,4 @@ --- Copyright (C) 2018 Free Software Foundation, Inc. +-- Copyright (C) 2018, 2020 Free Software Foundation, Inc. -- This file is part of the Cortex GNAT RTS package. -- @@ -18,8 +18,7 @@ with Ada.Interrupts.Names; with Ada.Real_Time; -with nrf51.GPIO; -with nrf51.GPIOTE; +with nRF.GPIO.Tasks_And_Events; package body Buttons is @@ -27,6 +26,7 @@ package body Buttons is for Button_Rep use (Button_A => 17, Button_B => 26); type Button_Data is record + Point : nRF.GPIO.GPIO_Point; State : Toggle := Off; Last_Time : Ada.Real_Time.Time := Ada.Real_Time.Time_First; end record; @@ -34,9 +34,17 @@ package body Buttons is type Buttons_Data is array (Button_Rep) of Button_Data; protected Button_Handler is + -- Only call one of these. + procedure Enable_Channel_Interrupts; + procedure Enable_Port_Interrupts; + function Button_State (Btn : Button_Rep) return Toggle; private - State : Buttons_Data; + State : Buttons_Data := + (Button_A => (Point => (Pin => Button_A'Enum_Rep), + others => <>), + Button_B => (Point => (Pin => Button_B'Enum_Rep), + others => <>)); procedure Handler with Attach_Handler => Ada.Interrupts.Names.GPIOTE_IRQ; end Button_Handler; @@ -47,51 +55,80 @@ package body Buttons is when B => Button_B)); protected body Button_Handler is + + procedure Enable_Channel_Interrupts is + use nRF.GPIO.Tasks_And_Events; + begin + Enable_Event (Chan => 0, + GPIO_Pin => Button_A'Enum_Rep, + Polarity => Falling_Edge); + Enable_Channel_Interrupt (Chan => 0); + Enable_Event (Chan => 1, + GPIO_Pin => Button_B'Enum_Rep, + Polarity => Falling_Edge); + Enable_Channel_Interrupt (Chan => 1); + end Enable_Channel_Interrupts; + + procedure Enable_Port_Interrupts is + begin + nRF.GPIO.Tasks_And_Events.Enable_Port_Interrupt; + end Enable_Port_Interrupts; + function Button_State (Btn : Button_Rep) return Toggle is (State (Btn).State); procedure Handler is - begin - nrf51.GPIOTE.GPIOTE_Periph.EVENTS_PORT := 0; - declare + use nRF.GPIO; + procedure Process_Event (For_Button : Button_Rep); + procedure Process_Event (For_Button : Button_Rep) is Now : constant Ada.Real_Time.Time := Ada.Real_Time.Clock; Other : constant array (Toggle) of Toggle := (Off => On, On => Off); - use nrf51.GPIO; use type Ada.Real_Time.Time; use type Ada.Real_Time.Time_Span; begin - for B in State'Range loop - if GPIO_Periph.IN_k.Arr (B'Enum_Rep) = Low - and then Now - State (B).Last_Time - > Ada.Real_Time.Milliseconds (25) - then - State (B).State := Other (State (B).State); - State (B).Last_Time := Now; - end if; - end loop; - end; + if not State (For_Button).Point.Set + and then Now - State (For_Button).Last_Time + > Ada.Real_Time.Milliseconds (50) -- debouncing + then + State (For_Button).State := Other (State (For_Button).State); + State (For_Button).Last_Time := Now; + end if; + end Process_Event; + begin + if Tasks_And_Events.Channel_Event_Set (Chan => 0) then + Tasks_And_Events.Acknowledge_Channel_Interrupt (Chan => 0); + Process_Event (Button_A); + end if; + if Tasks_And_Events.Channel_Event_Set (Chan => 1) then + Tasks_And_Events.Acknowledge_Channel_Interrupt (Chan => 1); + Process_Event (Button_B); + end if; + if Tasks_And_Events.Port_Event_Set then + Tasks_And_Events.Acknowledge_Port_Interrupt; + Process_Event (Button_A); + Process_Event (Button_B); + end if; end Handler; end Button_Handler; procedure Initialize; procedure Initialize is - use nrf51.GPIO; - use nrf51.GPIOTE; + use nRF.GPIO; + Config : constant GPIO_Configuration := + (Mode => Mode_In, + Resistors => Pull_Up, + Input_Buffer => Input_Buffer_Connect, + Sense => Sense_For_Low_Level, + others => <>); begin -- Buttons - GPIO_Periph.PIN_CNF (Button_A'Enum_Rep) := (DIR => Input, - INPUT => Connect, - PULL => Pullup, - SENSE => Low, - others => <>); - GPIO_Periph.PIN_CNF (Button_B'Enum_Rep) := (DIR => Input, - INPUT => Connect, - PULL => Pullup, - SENSE => Low, - others => <>); - - GPIOTE_Periph.INTENSET.PORT := Set; + Configure_IO (This => (Pin => Button_A'Enum_Rep), + Config => Config); + Configure_IO (This => (Pin => Button_B'Enum_Rep), + Config => Config); + + Button_Handler.Enable_Channel_Interrupts; end Initialize; begin diff --git a/test-microbit/testbed.adb b/test-microbit/circle.adb similarity index 94% rename from test-microbit/testbed.adb rename to test-microbit/circle.adb index b41f66f..cb0f8fe 100644 --- a/test-microbit/testbed.adb +++ b/test-microbit/circle.adb @@ -1,4 +1,4 @@ --- Copyright (C) 2018 Free Software Foundation, Inc. +-- Copyright (C) 2018,2020 Free Software Foundation, Inc. -- This file is part of the Cortex GNAT RTS package. -- @@ -24,7 +24,7 @@ pragma Unreferenced (Lights); with Ada.Real_Time; -procedure Testbed is +procedure Circle is -- These are the default values of the stack control parameters. @@ -51,4 +51,4 @@ procedure Testbed is begin delay until Ada.Real_Time.Time_Last; -end Testbed; +end Circle; diff --git a/test-microbit/event_support.adb b/test-microbit/event_support.adb new file mode 100644 index 0000000..f11ca28 --- /dev/null +++ b/test-microbit/event_support.adb @@ -0,0 +1,55 @@ +-- Copyright (C) 2020 Free Software Foundation, Inc. + +-- This file is part of the Cortex GNAT RTS package. +-- +-- The Cortex GNAT RTS package is free software; you can redistribute +-- it and/or modify it under the terms of the GNU General Public +-- License as published by the Free Software Foundation; either +-- version 3 of the License, or (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-- General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; see the file COPYING3. If not, see +-- . + +package body Event_Support is + + protected body LED_Event_Handling is + + procedure Handle + (Event : in out Ada.Real_Time.Timing_Events.Timing_Event) + is + Our_Event : LED_Event + renames LED_Event + (Ada.Real_Time.Timing_Events.Timing_Event'Class (Event)); + New_State : constant Boolean := Our_Event.State; + Flash : constant Milliseconds := 250; + use type Ada.Real_Time.Time; + begin + Set_LEDs (Our_Event.Row, Our_Event.Col) := New_State; + Our_Event.State := not New_State; + LEDs.Clear_All_LEDs; + for R in LEDs.Coord loop + for C in LEDs.Coord loop + if Set_LEDs (R, C) then + LEDs.Set_One_LED (R, C); + end if; + end loop; + end loop; + -- turn off after Flash, turn on after the event's Period + -- minus Flash + Event.Set_Handler + (Handler => Handler, + At_Time => Ada.Real_Time.Clock + + Ada.Real_Time.Milliseconds (if New_State + then Flash + else Our_Event.Period - Flash)); + end Handle; + + end LED_Event_Handling; + +end Event_Support; diff --git a/test-microbit/event_support.ads b/test-microbit/event_support.ads new file mode 100644 index 0000000..c5cde7a --- /dev/null +++ b/test-microbit/event_support.ads @@ -0,0 +1,54 @@ +-- Copyright (C) 2020 Free Software Foundation, Inc. + +-- This file is part of the Cortex GNAT RTS package. +-- +-- The Cortex GNAT RTS package is free software; you can redistribute +-- it and/or modify it under the terms of the GNU General Public +-- License as published by the Free Software Foundation; either +-- version 3 of the License, or (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-- General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; see the file COPYING3. If not, see +-- . + +with LEDs; +with Ada.Real_Time.Timing_Events; +package Event_Support is + + subtype Milliseconds is Natural; + + type LED_Event is new Ada.Real_Time.Timing_Events.Timing_Event + with record + Row : LEDs.Coord; + Col : LEDs.Coord; + Period : Milliseconds; + State : Boolean; + end record; + + Slow : LED_Event := + (Ada.Real_Time.Timing_Events.Timing_Event + with 4, 5, 5000, True); + Quick : LED_Event := + (Ada.Real_Time.Timing_Events.Timing_Event + with 1, 1, 2000, True); + + type LEDs_Status is array (LEDs.Coord, LEDs.Coord) of Boolean; + -- (Row, Col) + + protected LED_Event_Handling is + pragma Interrupt_Priority; + procedure Handle + (Event : in out Ada.Real_Time.Timing_Events.Timing_Event); + private + Set_LEDs : LEDs_Status := (others => (others => False)); + end LED_Event_Handling; + + Handler : constant Ada.Real_Time.Timing_Events.Timing_Event_Handler + := LED_Event_Handling.Handle'Access; + +end Event_Support; diff --git a/test-microbit/events.adb b/test-microbit/events.adb new file mode 100644 index 0000000..dea22c9 --- /dev/null +++ b/test-microbit/events.adb @@ -0,0 +1,40 @@ +-- Copyright (C) 2020 Free Software Foundation, Inc. + +-- This file is part of the Cortex GNAT RTS package. +-- +-- The Cortex GNAT RTS package is free software; you can redistribute +-- it and/or modify it under the terms of the GNU General Public +-- License as published by the Free Software Foundation; either +-- version 3 of the License, or (at your option) any later version. +-- +-- This program is distributed in the hope that it will be useful, +-- but WITHOUT ANY WARRANTY; without even the implied warranty of +-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +-- General Public License for more details. +-- +-- You should have received a copy of the GNU General Public License +-- along with this program; see the file COPYING3. If not, see +-- . + +with Event_Support; +with Ada.Real_Time.Timing_Events; +-- with Hardfault_Handling; +-- pragma Unreferenced (Hardfault_Handling); +procedure Events is + -- Environment_Task_Storage_Size : constant Natural := 1536 + -- with + -- Export, + -- Convention => Ada, + -- External_Name => "_environment_task_storage_size"; + -- Default_Initial_Stack : constant Natural := 4096 + -- with + -- Export, + -- Convention => Ada, + -- External_Name => "_default_initial_stack"; +begin + Event_Support.LED_Event_Handling.Handle + (Ada.Real_Time.Timing_Events.Timing_Event (Event_Support.Slow)); + Event_Support.Handler + (Ada.Real_Time.Timing_Events.Timing_Event (Event_Support.Quick)); + delay until Ada.Real_Time.Time_Last; +end Events; diff --git a/test-microbit/leds.adb b/test-microbit/leds.adb index 77d3525..d97d220 100644 --- a/test-microbit/leds.adb +++ b/test-microbit/leds.adb @@ -16,7 +16,7 @@ -- along with this program; see the file COPYING3. If not, see -- . -with nrf51.GPIO; +with nRF.GPIO; package body LEDs is @@ -31,10 +31,26 @@ package body LEDs is type Row_Pin is (R1, R2, R3); for Row_Pin use (R1 => 13, R2 => 14, R3 => 15); + Row_Points : array (Row_Pin) of nRF.GPIO.GPIO_Point + := (R1 => (Pin => R1'Enum_Rep), + R2 => (Pin => R2'Enum_Rep), + R3 => (Pin => R3'Enum_Rep)); + type Col_Pin is (C1, C2, C3, C4, C5, C6, C7, C8, C9); for Col_Pin use (C1 => 4, C2 => 5, C3 => 6, C4 => 7, C5 => 8, C6 => 9, C7 => 10, C8 => 11, C9 => 12); + Col_Points : array (Col_Pin) of nRF.GPIO.GPIO_Point + := (C1 => (Pin => C1'Enum_Rep), + C2 => (Pin => C2'Enum_Rep), + C3 => (Pin => C3'Enum_Rep), + C4 => (Pin => C4'Enum_Rep), + C5 => (Pin => C5'Enum_Rep), + C6 => (Pin => C6'Enum_Rep), + C7 => (Pin => C7'Enum_Rep), + C8 => (Pin => C8'Enum_Rep), + C9 => (Pin => C9'Enum_Rep)); + type LED_Pins is record R : Row_Pin; C : Col_Pin; @@ -48,38 +64,39 @@ package body LEDs is ((R3, C3), (R2, C7), (R3, C1), (R2, C6), (R3, C2))); procedure Clear_All_LEDs is - use nrf51.GPIO; + use nRF.GPIO; begin for R in Row_Pin loop - GPIO_Periph.OUT_k.Arr (R'Enum_Rep) := Low; + Row_Points (R).Clear; end loop; for C in Col_Pin loop - GPIO_Periph.OUT_k.Arr (C'Enum_Rep) := High; + Col_Points (C).Set; end loop; end Clear_All_LEDs; procedure Set_One_LED (Row, Col : Coord) is Pins : constant LED_Pins := LEDs (Row, Col); - use nrf51.GPIO; + use nRF.GPIO; begin - GPIO_Periph.OUT_k.Arr (Pins.R'Enum_Rep) := High; - GPIO_Periph.OUT_k.Arr (Pins.C'Enum_Rep) := Low; + Row_Points (Pins.R).Set; + Col_Points (Pins.C).Clear; end Set_One_LED; procedure Initialize; procedure Initialize is - use nrf51.GPIO; + use nRF.GPIO; + Config : constant GPIO_Configuration := (Mode => Mode_Out, + Resistors => Pull_Up, + others => <>); begin -- LED matrix for R in Row_Pin loop - GPIO_Periph.PIN_CNF (R'Enum_Rep) := (DIR => Output, - PULL => Pullup, - others => <>); + Configure_IO (This => (Pin => R'Enum_Rep), + Config => Config); end loop; for C in Col_Pin loop - GPIO_Periph.PIN_CNF (C'Enum_Rep) := (DIR => Output, - PULL => Pullup, - others => <>); + Configure_IO (This => (Pin => C'Enum_Rep), + Config => Config); end loop; Clear_All_LEDs; diff --git a/test-microbit/lights.adb b/test-microbit/lights.adb index 70afa14..c823c84 100644 --- a/test-microbit/lights.adb +++ b/test-microbit/lights.adb @@ -1,4 +1,4 @@ --- Copyright (C) 2018 Free Software Foundation, Inc. +-- Copyright (C) 2018, 2020 Free Software Foundation, Inc. -- This file is part of the Cortex GNAT RTS package. -- @@ -34,19 +34,13 @@ package body Lights is type Coord_Pair is record R : Coord; C : Coord; - Scaling : Positive; -- multiplies basic interval end record; type LED_Sequence is array (Positive range <>) of Coord_Pair; - Spiral_Clockwise : constant LED_Sequence := - ((1, 1, 1), (1, 2, 1), (1, 3, 1), (1, 4, 1), (1, 5, 1), - (2, 5, 1), (3, 5, 1), (4, 5, 1), (5, 5, 1), - (5, 4, 1), (5, 3, 1), (5, 2, 1), (5, 1, 1), - (4, 1, 1), (3, 1, 1), (2, 1, 1), - (2, 2, 2), (2, 3, 2), (2, 4, 2), - (3, 4, 2), (4, 4, 2), - (4, 3, 2), (4, 2, 2), - (3, 2, 3), - (3, 3, 4)); + Clockwise : constant LED_Sequence := + ((1, 1), (1, 2), (1, 3), (1, 4), (1, 5), + (2, 5), (3, 5), (4, 5), (5, 5), + (5, 4), (5, 3), (5, 2), (5, 1), + (4, 1), (3, 1), (2, 1)); function Interval return Ada.Real_Time.Time_Span is (case Buttons.Button_State (Buttons.A) is @@ -60,18 +54,18 @@ package body Lights is loop case Buttons.Button_State (Buttons.B) is when Buttons.Off => - for S of Spiral_Clockwise loop + for S of Clockwise loop exit when Buttons.Button_State (Buttons.B) = Buttons.On; Clear_All_LEDs; Set_One_LED (S.R, S.C); - delay until Ada.Real_Time.Clock + Interval * S.Scaling; + delay until Ada.Real_Time.Clock + Interval; end loop; when Buttons.On => - for S of reverse Spiral_Clockwise loop + for S of reverse Clockwise loop exit when Buttons.Button_State (Buttons.B) = Buttons.Off; Clear_All_LEDs; Set_One_LED (S.R, S.C); - delay until Ada.Real_Time.Clock + Interval * S.Scaling; + delay until Ada.Real_Time.Clock + Interval; end loop; end case; end loop; diff --git a/test-microbit/testbed.gpr b/test-microbit/tests.gpr similarity index 90% rename from test-microbit/testbed.gpr rename to test-microbit/tests.gpr index 6db7da4..1458c82 100644 --- a/test-microbit/testbed.gpr +++ b/test-microbit/tests.gpr @@ -1,4 +1,4 @@ --- Copyright (C) 2018 Free Software Foundation, Inc. +-- Copyright (C) 2018, 2020 Free Software Foundation, Inc. -- -- This file is part of the Cortex GNAT RTS package. -- @@ -16,9 +16,11 @@ -- along with this program; see the file COPYING3. If not, see -- . -project Testbed is +with "Ada_Drivers_Library/ada_drivers_library"; - for Main use ("seconds.adb", "testbed.adb"); +project Tests is + + for Main use ("circle.adb", "events.adb", "seconds.adb"); for Languages use ("Ada"); for Source_Dirs use (".", "../test-common"); for Object_Dir use ".build"; @@ -62,4 +64,4 @@ project Testbed is for Communication_Protocol use "remote"; end IDE; -end Testbed; +end Tests;