Blinking an LED on the UP.. Sounds simple?
If you have done the below correctly you should have an outcome as this:
(or if you are lazy, download the project HERE)
If you have done the below correctly you should have an outcome as this:
(or if you are lazy, download the project HERE)
UP LED FIRST....
The majority of "makers" being targeted by the myriad of new SBC's on the market are not professional coders, most are not even amateur coders.. for the large part they are people like me.. interested in learning a new technology, and willing to google for snippets and copy-paste a working program together.
The success of boards like the Raspberry Pi and the Arduino series are largely due to their plain English, down to earth API's, aimed at "makers" with ample clear instructions and tutorials making the learning curve fast.
SO: it was a little disappointing to have run into such a lot of headaches with my UP Board, and so little documentation to try figure it out. Anyhow, getting back to Blink...
SO: it was a little disappointing to have run into such a lot of headaches with my UP Board, and so little documentation to try figure it out. Anyhow, getting back to Blink...
Lets examine this simplest of programs on a few other platforms.. lighting up an LED.
Arduino:
ledPin = 3;
pinMode(ledPin, OUPUT);
digitalWrite(ledPin, HIGH)
pinMode(ledPin, OUPUT);
digitalWrite(ledPin, HIGH)
RPi running IoT:
using Windows.Devices.Gpio;
ledPin = gpio.OpenPin(3);
ledPin.SetDriveMode(GpioPinDriveMode.Output);
ledPin.Write(GpioPinValue.High);
ledPin = gpio.OpenPin(3);
ledPin.SetDriveMode(GpioPinDriveMode.Output);
ledPin.Write(GpioPinValue.High);
RPi running Rasbian:
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.Board)
ledPin = 3
GPIO.setup(ledPin,GPIO.OUT)
GPIO.output(ledPin,GPIO.HIGH)
There is a commonality of implementation that makes it simple to understand the process..
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.Board)
ledPin = 3
GPIO.setup(ledPin,GPIO.OUT)
GPIO.output(ledPin,GPIO.HIGH)
There is a commonality of implementation that makes it simple to understand the process..
include a library if required,
set the pin direction,
set the pin value.
Now lets examine doing the the same on UP Board, using C# in windows 10.
Firstly the SETUP Steps:
You will need to download the SDK and Framework, below are the ones used in this example. I don't maintain these files so they are subject to change.
SDK: http://www.dropbox.com/s/uamv9p4tt5881jm/Dio.rar?dl=0
FrameWork : http://www.dropbox.com/s/ha0nxu0kmdnfta9/Hi-Safe_v2_20161017.rar?dl=0
The framework contains some drivers. Install the drivers using the adequate advice in the PDF in the folder.
In the SDK is an example project called DIO, (written in CS).
SDK: http://www.dropbox.com/s/uamv9p4tt5881jm/Dio.rar?dl=0
FrameWork : http://www.dropbox.com/s/ha0nxu0kmdnfta9/Hi-Safe_v2_20161017.rar?dl=0
The framework contains some drivers. Install the drivers using the adequate advice in the PDF in the folder.
In the SDK is an example project called DIO, (written in CS).
Copy the DIO project to a handy location and copy out the file aaeonEAPI.dll. Now open the DIO project in VS and leave it open.. we will need to copy some stuff over later.
(if you attempt to compile the project as is in VS15 you will hit a wall, search my name CeeBee on the UP forum for instructions on how to bypass this issue, but for now we only want to copy files from this project, not run it, so onwards...)
Create a new Project:
(if you attempt to compile the project as is in VS15 you will hit a wall, search my name CeeBee on the UP forum for instructions on how to bypass this issue, but for now we only want to copy files from this project, not run it, so onwards...)
Create a new Project:
In your new project right click the project name in solution explorer, and then [ADD EXISTING]. Add the aaeonEAPI.dll file we copied out earlier, then set the aaeonEAPI.dll to "copy always" in properties.
Now lets go back to the DIO projects main application code and copy and paste the lines near the top of it which import the DLL calls from the aaeonEAPI.dll, into your program.
Open and copy all the content EAPI.CS file main body.
(its been done in the region wrappers in the code below)
Open and copy all the content EAPI.CS file main body.
(its been done in the region wrappers in the code below)
Now finally you are ready to start actually coding.. you can close the DIO example.
Returning to our examples above we can immediately write the following code and expect a result.
EApiLibInitialize(); LedPin =3; EApiGPIOSetDirection(EAPI.EAPI_GPIO_GPIO_ID((UInt32)(ledPin)), 0xFFFFFFFF, 0) EApiGPIOSetLevel(EAPI.EAPI_GPIO_GPIO_ID((UInt32)(ledPin)), 0xFFFFFFFF, 1)
BUT... It didn't work, did it? The current API has a glitch, either by mistake or by design the pin numbering is out by -1... changing 3 to 2 in example above woudl make pin 3 light up...
BUT, what is input, what is output, what is high, what is low, and boy is that code ugly, all those uint's and 0xFFFFFFFF's which we have no idea about, why are we looking at them?
SO, lets fix that.. and make it look prettier..
(and fix that pesky bug)
(and fix that pesky bug)
Add these variables to the top of your code,and then add these two voids into your code
(these are the most basic examples to get it working without any error checking code!!)
private uint HIGH = 1, LOW = 0, INPUT = 1, OUTPUT = 0; public void PinMode(int pin, uint dir) pin = pin - 1; EApiGPIOSetDirection(EAPI.EAPI_GPIO_GPIO_ID((UInt32)(pin)), 0xFFFFFFFF, dir);}
public void DigitalWrite(int pin, uint state) pin = pin - 1; EApiGPIOSetLevel(EAPI.EAPI_GPIO_GPIO_ID((UInt32)(pin)), 0xFFFFFFFF, state);}
Which will now allow you to write code using a more common kind of expression like
and PIN3 will now fire up happily...
EApiLibInitialize(); ledPin= 3; PinMode(ledPin,OUTPUT); DigitalWrite(ledPin,HIGH);
and PIN3 will now fire up happily...
This is also now far more legible, noting you can call these voids anything you like, or return an error etc.
..its my void, and I'll can int if I want to... <sung to "It's my Party" - Leslie Gore>
If you own your board, and the code is for you, to be added to existing projects, you don't need to go much past this,
For the rest, lets move onto SuperBlinky...
BLINKY
So the first actual "Blinky" program for the UP board... .. based on the above cleanup and fixes, its a little beefier, with selectable pin, selectable millisecond delay and the number of repeats.. and some basic error catch.
(you can delete the form, BlinkPin and Start_Click and basically have a template ready to start working in.)
Methods created are :
EnableSDIO()
which with return with an int ERR if there is one.
SetPinDirection(int pin, uint direction)
which will accept the pin number and either INPUT or OUTPUT as a uint variable, it will return an int err if it went kooky on you.(status.text is updated)
GetPinDirection(int pin, uint direction)
which will accept the pin number and a variable to pass to the API for the pin direction. it will return and int of either ERR (status.text is updated) or 1(input) or 0(output).
SetPinState(int pin, uint state)
which will accept the pin number and either HIGH or LOW as a uint variable, it will return an int ERR if it went kooky on you. (status.text is updated)
GetPinState(int pin, uint state)
which will accept the pin number and a variable to pass to the API for the pin state. it will return and int of either ERR (status.text is updated) or 1(high) or 0(low).
(errors and values as int as its a PITA to keep having to convert between uint's to do if/then compares to other ints, change as required)
You will need to create a form with these components
And this code.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | using System; using System.Drawing; using System.Runtime.InteropServices; using System.Threading.Tasks; using System.Windows.Forms; namespace UP_Blinky { public partial class Blinky : Form { #region Import DLL Calls [DllImport("aaeonEAPI.dll", EntryPoint = "EApiGPIOGetDirectionCaps")] public static extern UInt32 EApiGPIOGetDirectionCaps(uint Id, ref UInt32 pInputs, ref UInt32 pOutputs); [DllImport("aaeonEAPI.dll", EntryPoint = "EApiGPIOGetDirection")] public static extern UInt32 EApiGPIOGetDirection(UInt32 Id, UInt32 Bitmask, ref UInt32 pDirection); [DllImport("aaeonEAPI.dll", EntryPoint = "EApiGPIOSetDirection")] public static extern UInt32 EApiGPIOSetDirection(UInt32 Id, UInt32 Bitmask, UInt32 Direction); [DllImport("aaeonEAPI.dll", EntryPoint = "EApiGPIOGetLevel")] public static extern UInt32 EApiGPIOGetLevel(UInt32 Id, UInt32 Bitmask, ref UInt32 pLevel); [DllImport("aaeonEAPI.dll", EntryPoint = "EApiGPIOSetLevel")] public static extern UInt32 EApiGPIOSetLevel(UInt32 Id, UInt32 Bitmask, UInt32 Level); [DllImport("aaeonEAPI.dll", EntryPoint = "EApiGPIOGetCaps")] public static extern UInt32 EApiGPIOGetCaps(UInt32 Id, ref UInt32 PinCount, ref UInt32 pDioDisable); [DllImport("aaeonEAPI.dll", EntryPoint = "EApiLibInitialize")] public static extern UInt32 EApiLibInitialize(); [DllImport("aaeonEAPI.dll", EntryPoint = "EApiLibUnInitialize")] public static extern UInt32 EApiLibUnInitialize(); #endregion #region My Variables private uint HIGH = 1; private uint LOW = 0; private uint INPUT = 1; private uint OUTPUT = 0; #endregion #region Status Codes public const UInt32 EAPI_STATUS_NOT_INITIALIZED = 0xFFFFFFFF; public const UInt32 EAPI_STATUS_INITIALIZED = 0xFFFFFFFE; public const UInt32 EAPI_STATUS_ALLOC_ERROR = 0xFFFFFFFD; public const UInt32 EAPI_STATUS_DRIVER_TIMEOUT = 0xFFFFFFFC; public const UInt32 EAPI_STATUS_INVALID_PARAMETER = 0xFFFFFEFF; public const UInt32 EAPI_STATUS_INVALID_BLOCK_ALIGNMENT = 0xFFFFFEFE; public const UInt32 EAPI_STATUS_INVALID_BLOCK_LENGTH = 0xFFFFFEFD; public const UInt32 EAPI_STATUS_INVALID_DIRECTION = 0xFFFFFEFC; public const UInt32 EAPI_STATUS_INVALID_BITMASK = 0xFFFFFEFB; public const UInt32 EAPI_STATUS_RUNNING = 0xFFFFFEFA; public const UInt32 EAPI_STATUS_UNSUPPORTED = 0xFFFFFCFF; public const UInt32 EAPI_STATUS_NOT_FOUND = 0xFFFFFBFF; public const UInt32 EAPI_STATUS_TIMEOUT = 0xFFFFFBFE; public const UInt32 EAPI_STATUS_BUSY_COLLISION = 0xFFFFFBFD; public const UInt32 EAPI_STATUS_READ_ERROR = 0xFFFFFAFF; public const UInt32 EAPI_STATUS_WRITE_ERROR = 0xFFFFFAFE; public const UInt32 EAPI_STATUS_MORE_DATA = 0xFFFFF9FF; public const UInt32 EAPI_STATUS_ERROR = 0xFFFFF0FF; public const UInt32 EAPI_STATUS_SUCCESS = 0x00000000; #endregion #region Board Hardware Info Strings public const UInt32 EAPI_ID_BOARD_MANUFACTURER_STR = 0; public const UInt32 EAPI_ID_BOARD_NAME_STR = 1; public const UInt32 EAPI_ID_BOARD_REVISION_STR = 2; public const UInt32 EAPI_ID_BOARD_SERIAL_STR = 3; public const UInt32 EAPI_ID_BOARD_BIOS_REVISION_STR = 4; public const UInt32 EAPI_ID_BOARD_HW_REVISION_STR = 5; public const UInt32 EAPI_ID_BOARD_PLATFORM_TYPE_STR = 6; public const UInt32 EAPI_ID_GET_EAPI_SPEC_VERSION = 0; public const UInt32 EAPI_ID_BOARD_BOOT_COUNTER_VAL = 1; public const UInt32 EAPI_ID_BOARD_RUNNING_TIME_METER_VAL = 2; public const UInt32 EAPI_ID_BOARD_PNPID_VAL = 3; public const UInt32 EAPI_ID_BOARD_PLATFORM_REV_VAL = 4; public const UInt32 EAPI_ID_AONCUS_HISAFE_FUCTION = 5; public const UInt32 EAPI_ID_BOARD_DRIVER_VERSION_VAL = 0x10000; public const UInt32 EAPI_ID_BOARD_LIB_VERSION_VAL = 0x10001; public const UInt32 EAPI_ID_HWMON_CPU_TEMP = 0x20000; public const UInt32 EAPI_ID_HWMON_CHIPSET_TEMP = 0x20001; public const UInt32 EAPI_ID_HWMON_SYSTEM_TEMP = 0x20002; public const UInt32 EAPI_KELVINS_OFFSET = 2731; public static UInt32 EAPI_ENCODE_CELCIUS(UInt32 Celsius) { return (Celsius * 10) + EAPI_KELVINS_OFFSET; } public static UInt32 EAPI_DECODE_CELCIUS(UInt32 Celsius) { return ((Celsius) - EAPI_KELVINS_OFFSET) / 10; } public const UInt32 EAPI_ID_HWMON_VOLTAGE_VCORE = 0x21004; public const UInt32 EAPI_ID_HWMON_VOLTAGE_2V5 = 0x21008; public const UInt32 EAPI_ID_HWMON_VOLTAGE_3V3 = 0x2100C; public const UInt32 EAPI_ID_HWMON_VOLTAGE_VBAT = 0x21010; public const UInt32 EAPI_ID_HWMON_VOLTAGE_5V = 0x21014; public const UInt32 EAPI_ID_HWMON_VOLTAGE_5VSB = 0x21018; public const UInt32 EAPI_ID_HWMON_VOLTAGE_12V = 0x2101C; public const UInt32 EAPI_ID_HWMON_VOLTAGE_DIMM = 0x21020; public const UInt32 EAPI_ID_HWMON_VOLTAGE_3VSB = 0x21024; public const UInt32 EAPI_ID_HWMON_FAN_CPU = 0x22000; public const UInt32 EAPI_ID_HWMON_FAN_CHIPSET = 0x22001; public const UInt32 EAPI_ID_HWMON_FAN_SYSTEM = 0x22002; public const UInt32 EAPI_ID_BACKLIGHT_1 = 0; public const UInt32 EAPI_ID_BACKLIGHT_2 = 1; public const UInt32 EAPI_ID_BACKLIGHT_3 = 2; public const UInt32 EAPI_BACKLIGHT_SET_ON = 0; public const UInt32 EAPI_BACKLIGHT_SET_OFF = 0xFFFFFFFF; public const UInt32 EAPI_BACKLIGHT_SET_DIMEST = 0; public const UInt32 EAPI_BACKLIGHT_SET_BRIGHTEST = 255; public const UInt32 EAPI_ID_STORAGE_STD = 0; public const UInt32 EAPI_ID_I2C_EXTERNAL = 0; public const UInt32 EAPI_ID_I2C_LVDS_1 = 1; public const UInt32 EAPI_ID_I2C_LVDS_2 = 2; public UInt32 EAPI_I2C_ENC_7BIT_ADDR(UInt32 x) { return ((x) & 0x07F) << 1; } public UInt32 EAPI_I2C_DEC_7BIT_ADDR(UInt32 x) { return ((x) >> 1) & 0x07F; } #endregion #region GPIO public static UInt32 EAPI_GPIO_GPIO_ID(UInt32 GPIO_NUM) { return GPIO_NUM; } public const UInt32 EAPI_GPIO_GPIO_BITMASK = 1; public UInt32 EAPI_ID_GPIO_GPIO00 = EAPI_GPIO_GPIO_ID(0); public UInt32 EAPI_ID_GPIO_GPIO01 = EAPI_GPIO_GPIO_ID(1); public UInt32 EAPI_ID_GPIO_GPIO02 = EAPI_GPIO_GPIO_ID(2); public UInt32 EAPI_ID_GPIO_GPIO03 = EAPI_GPIO_GPIO_ID(3); public UInt32 EAPI_ID_GPIO_GPIO04 = EAPI_GPIO_GPIO_ID(4); public UInt32 EAPI_ID_GPIO_GPIO05 = EAPI_GPIO_GPIO_ID(5); public UInt32 EAPI_ID_GPIO_GPIO06 = EAPI_GPIO_GPIO_ID(6); public UInt32 EAPI_ID_GPIO_GPIO07 = EAPI_GPIO_GPIO_ID(7); public static UInt32 EAPI_GPIO_BANK_ID(UInt32 GPIO_NUM) { return (0x10000 | ((GPIO_NUM) >> 5)); } public static int EAPI_GPIO_BANK_MASK(int GPIO_NUM) { return (0x01 << (GPIO_NUM & 0x1F)); } public UInt32 EAPI_ID_GPIO_BANK00 = EAPI_GPIO_BANK_ID(0); public UInt32 EAPI_ID_GPIO_BANK01 = EAPI_GPIO_BANK_ID(32); public UInt32 EAPI_ID_GPIO_BANK02 = EAPI_GPIO_BANK_ID(64); public const UInt32 EAPI_GPIO_BITMASK_SELECT = 1; public const UInt32 EAPI_GPIO_BITMASK_NOSELECT = 0; public const UInt32 EAPI_GPIO_LOW = 0; public const UInt32 EAPI_GPIO_HIGH = 1; public const UInt32 EAPI_GPIO_INPUT = 1; public const UInt32 EAPI_GPIO_OUTPUT = 0; #endregion public Blinky() { InitializeComponent(); EnableSDIO(); } #region Helpers private int EnableSDIO() { uint err = EApiLibInitialize(); if (err != EAPI_STATUS_INITIALIZED) { Status.Text = "Library did not Load"; Start.Enabled = false; return(int)err; } Status.Text = "Library good"; return (int)err; } public int SetPinDirection(int pin, uint direction) { uint err; pin = pin - 1; err = EApiGPIOSetDirection(EAPI_GPIO_GPIO_ID((UInt32)(pin)), 0xFFFFFFFF, direction); if (err > 0) { Status.Text = "Error #" + err; } return(int)err; } public int GetPinDirection(int pin, uint direction) { uint err; pin = pin - 1; err = EApiGPIOGetDirection(EAPI_GPIO_GPIO_ID((UInt32)(pin)), 0xFFFFFFFF, ref direction); if (err > 0) { Status.Text = "Error #" + err; return (int)err; } return (int)direction; } public int SetPinState(int pin, uint state) { uint err; pin = pin - 1; err = EApiGPIOSetLevel(EAPI_GPIO_GPIO_ID((UInt32)(pin)), 0xFFFFFFFF, state); if (err > 0) { Status.Text = "Error #" + err; } return (int)err; } public int GetPinState(int pin, uint state) { uint err; pin = pin - 1; err = EApiGPIOGetLevel(EAPI_GPIO_GPIO_ID((UInt32)(pin)), 0xFFFFFFFF, ref state); if (err > 0) { Status.Text = "Error #" + err; return(int)err; } return (int)state; } private void UP_Blinky_Closing(object sender, FormClosingEventArgs e) { //when we close the form, close the library EApiLibUnInitialize(); } #endregion private void Start_Click(object sender, EventArgs e) { int Pin = Decimal.ToInt32(PinNumberSelect.Value); int speed = Decimal.ToInt32(Speed.Value); int repeat = Decimal.ToInt32(repeatvalue.Value); BlinkPin(Pin,speed,repeat); } private async void BlinkPin(int Pin,int speed,int repeat) { SetPinDirection(Pin, OUTPUT); Status.Text = "Pin #" + Pin + " Set as OUTPUT"; await Task.Delay(TimeSpan.FromMilliseconds(speed)); for (int i = 0; i < repeat; i++) { Status.Text = "Pin #" + Pin + " Set HIGH"; LedBlinker.BackColor = Color.Red; SetPinState(Pin, HIGH); await Task.Delay(TimeSpan.FromMilliseconds(speed)); SetPinState(Pin, LOW); Status.Text = "Pin #" + Pin + " Set LOW"; LedBlinker.BackColor = Color.Black; await Task.Delay(TimeSpan.FromMilliseconds(speed)); } } } } |
and hopefully you get the same result as me, a nice easy to use blinker app!
(To keep yourself sane, use #region ~ #endregion wrappers to hide the stuff you don't want to see while you are working so your actual code ends up looking like bleow)
(To keep yourself sane, use #region ~ #endregion wrappers to hide the stuff you don't want to see while you are working so your actual code ends up looking like bleow)
In Conclusion:
I still don't know what a bitmask is, or how and why and when it would be used,
I still don't know how to write a PWM value, or read an analog pin...
Much work to be done deciphering the API documentation...
I still don't know how to write a PWM value, or read an analog pin...
Much work to be done deciphering the API documentation...
Thanks chris , i have some doubt , whenever i run the app , i am getting like lib not loaded. can help me out here please
ReplyDeleteIt means you have not installed the drivers and or copied the dlls over. Read the post carefully.
ReplyDeleteChris-
ReplyDeleteIs there any way you can share your code? None of the source links on this blog work. It seems that your google drive link is also down.
https://drive.google.com/open?id=0B5yCbfbC75zDbUUwZ0lidUtmYlU
Awesome starter. Thank you.
ReplyDelete