Small update:
If you have used the info supplied in my earlier articles here and here I am happy to announce that Adobe has fixed these issues in AIR3.4 and these hacks are no longer necessary.
In fact, if you want to use 32-bit colour in an Android AIR app, you need to ensure that you don't hack the Activity theme as this will result in forcing the app to 16-bit (something that had me scratching my head for a while!).
So thanks to Adobe for that, now if they can just fix the issues with URLLoader on 3.4+ and the ATF issues on nVidia based tablets then my life would get a lot easier...
If anyone from the Adobe AIR team reads this, please contact me! My team uses your product in ways you probably wouldn't believe and we are constantly pushing AIR to the limits of the technology. It would be awesome to partner with you on the issues we find.
-(e)
Friday, November 23, 2012
Implementing Artcfox's TLC5940 code on an Arduino, Part 3
Well its been a while... Real Life(tm) has been rather busy!
The code for this post has been gathering bit-rot on my drive so I thought it time to just put it up with a a short post (basically just a code dump) which I will follow up at a later point.
In the previous article we got the Arduino setup with appropriate clock fuse settings so that Matt's code would work. Based on this I took the sample code from CH9 and modified it to implement a small RGB pattern using some of the CH9 features, specifically the gamma correction.
CH9 is based around mulitplexing the output. I haven't used this as I don't have the transistors availabe to test it, so basically the output is still a direct drive of the attached LEDs with one colour per output pin on the TLC5940. However there is no reason that multiplexing shouldn't work. If you want to try it out, refer to Matt's original document and wire appropriately. If you apply the techniques discribed previously to the original CH9 code you should be good to go. You can use the attached code as a reference.
Hardware setup should be the same as per the first article. To see the correct visual output, wire each leg of an RGB LED to output pins 0,1,2 (R,G,B) then 3,4,5 etc. for a total of 4 LEDs. Then compile and upload the sketch and you should be good to go. The code will colour fade between each rainbow colour.
The code is available here. Go get it!
Next time I get a chance to get to the local electronics supplier I'll buy some of the appropriate transistors and wire up for the multiplexing capabilities of Matt's library and post up some wiring info and more code.
For questions etc, follow me:
or mail me at: sweetlilmre (at) gmail (dot) com
-(e)
The code for this post has been gathering bit-rot on my drive so I thought it time to just put it up with a a short post (basically just a code dump) which I will follow up at a later point.
In the previous article we got the Arduino setup with appropriate clock fuse settings so that Matt's code would work. Based on this I took the sample code from CH9 and modified it to implement a small RGB pattern using some of the CH9 features, specifically the gamma correction.
CH9 is based around mulitplexing the output. I haven't used this as I don't have the transistors availabe to test it, so basically the output is still a direct drive of the attached LEDs with one colour per output pin on the TLC5940. However there is no reason that multiplexing shouldn't work. If you want to try it out, refer to Matt's original document and wire appropriately. If you apply the techniques discribed previously to the original CH9 code you should be good to go. You can use the attached code as a reference.
Hardware setup should be the same as per the first article. To see the correct visual output, wire each leg of an RGB LED to output pins 0,1,2 (R,G,B) then 3,4,5 etc. for a total of 4 LEDs. Then compile and upload the sketch and you should be good to go. The code will colour fade between each rainbow colour.
The code is available here. Go get it!
Next time I get a chance to get to the local electronics supplier I'll buy some of the appropriate transistors and wire up for the multiplexing capabilities of Matt's library and post up some wiring info and more code.
For questions etc, follow me:
or mail me at: sweetlilmre (at) gmail (dot) com
-(e)
Thursday, July 5, 2012
Implementing Artcfox's TLC5940 code on an Arduino, Part 2
In my last post I detailed the basic hardware and software setup for getting Matt's TLC5940 chapter 3 code working on an Arduino.
The the code doesn't do too much, but with the hardware and software working we can start to explore later chapters (where the interesting stuff happens).
At this point there is one more hardware obstacle to overcome. Matt makes use of an interesting feature of the Atmega328p called CKOUT. This is a chip level setting that can (according to the 328p datasheet) "output the system clock on the CLKO pin". Matt uses this to drive the TLC5940's GSCLK pin, a very clever way of handling the timing between the two chips.
Unfortunately the Arduino is not configured to support this by default and in order to switch on this feature, special configuration values in the 328p's flash known as "fuses" need to be be set. To do that, you need a chip level programmer.
The programmer I use is an USBtiny2 clone that I got off eBay for about 10 USD (search for "usbtiny" or "usbtinyasp" and you should get many results). Alternatively you can use a second Arduino to accomplish the same thing as per this link. Lastly, if you want to support a really fantastic company and get a great programmer with a nice case, please consider this one from Adafruit.
From this point on I will be assuming that you are using the USBtiny programmer, are on a Windows machine and are intending to program the fuses of an Arduino UNO.
At this point I am assuming that you have managed to install the drivers for your programmer. If you are using the USBtiny and are on Windows7 64-bit, this link may be helpful. If not, visit this excellent tutorial at Adafruit and get the drivers installed.
Once you have the hardware, you need to get hold of AVRDUDE. This is the software that will talk to your programmer and allow you to set the fuse bits. As of this article the latest AVRDUDE version is 5.1.1 and can be found here. If you are using an alternative programmer, please check compatibility with AVRDUDE at this page (look for the "
Grab the windows archive (avrdude-5.11-Patch7610-win32.zip) and extract to a convenient location. I used "C:\temp\avrdude". Now you will need to connect your programmer to your Arduino.
Using the supplied 6 pin cable connect the programmer to the ICSP port on your Arduino, making sure you have:
Once you have the cable correctly connected, connect the programmer to usb and the Arduino should power on.
Assuming everything is good to go: open a command prompt, change to the directory you extracted the AVRDUDE software into earlier ("c:\temp\avrdude" for me) and type:
See the advanced notes for additional information.
This command should print out something pretty much like this:
If you get this result, add a "-v" to the command:
which should spew out a whole load of text ending in something that looks like this:
What we want to do is to change the value of the lfuse from 0xFF to 0xBF to enable CKOUT.
To verify this, open this awesome AVR fuse calculator in another tab / window and check the lfuse checkbox that reads "Clock output on PORTB0; [CKOUT=0]". You should see the calculated value for lfuse change from 0xFF to 0xBF (and back when you uncheck the option).
Before we proceed any further, a word of caution:
If your fuse settings are not the same as the screenshot above you probably shouldn't proceed unless you are sure you know what you are doing.
Some clarification: You need to know that you have a good fuse read at this point. Your values may be different to mine but as long as they are good values you'll be okay.
Thanks to +Al McElmon who reported his hfuse value as D6 not DE. In the fuse calculator you can see that this is because EESAVE has been enabled. This could possibly be a setting on later Arduino Models?
Finally, if everything checks out and you are 100% sure of this, we are one command away from completion:
This command will write the value 0xBF to the lfuse and set CKOUT.
For a breakdown the "-U" command above, the command:
And there we have it. Your Arduino should now be in a state where we can move onto the more advanced chapters of Matt's book.
Next time we are going to do exactly that, I hope you've enjoyed this post.
Until then, happy hacking!
-(e)
p.s. If you get stuck, I can attempt to help you out, circle me on G+ and send me a message via Messenger, or post a comment and I'll see what I can do.
Advanced Notes:
Perhaps you have a different model of Arduino? (e.g. ATMega168 e.t.c.):
The "-p m328p" switch for AVRDUDE specifies what chip your Arduino has. The "m328p" value is valid for the Arduino UNO and several other models, but will have to be changed for alternative models.
In this case, when using the fuse calculator please input your values for lfuse, hfuse and efuse into the fuse calculator, ensure that you have the correct AVR chip selected and note the change in the lfuse value when CKOUT is selected. The point here is that we wish to change ONLY this value. You can also confirm default board fuse settings in the "boards.txt" file located in the "hardware\arduino" directory of the Arduino IDE installation.
AVRDUDE has many other switches and supports many other programmers. I would suggest that you check out the command line in the documentation.
At this point there is one more hardware obstacle to overcome. Matt makes use of an interesting feature of the Atmega328p called CKOUT. This is a chip level setting that can (according to the 328p datasheet) "output the system clock on the CLKO pin". Matt uses this to drive the TLC5940's GSCLK pin, a very clever way of handling the timing between the two chips.
Unfortunately the Arduino is not configured to support this by default and in order to switch on this feature, special configuration values in the 328p's flash known as "fuses" need to be be set. To do that, you need a chip level programmer.
The programmer I use is an USBtiny2 clone that I got off eBay for about 10 USD (search for "usbtiny" or "usbtinyasp" and you should get many results). Alternatively you can use a second Arduino to accomplish the same thing as per this link. Lastly, if you want to support a really fantastic company and get a great programmer with a nice case, please consider this one from Adafruit.
From this point on I will be assuming that you are using the USBtiny programmer, are on a Windows machine and are intending to program the fuses of an Arduino UNO.
At this point I am assuming that you have managed to install the drivers for your programmer. If you are using the USBtiny and are on Windows7 64-bit, this link may be helpful. If not, visit this excellent tutorial at Adafruit and get the drivers installed.
Once you have the hardware, you need to get hold of AVRDUDE. This is the software that will talk to your programmer and allow you to set the fuse bits. As of this article the latest AVRDUDE version is 5.1.1 and can be found here. If you are using an alternative programmer, please check compatibility with AVRDUDE at this page (look for the "
-c programmer-id"
reference).Grab the windows archive (avrdude-5.11-Patch7610-win32.zip) and extract to a convenient location. I used "C:\temp\avrdude". Now you will need to connect your programmer to your Arduino.
Arduino ICSP port |
Using the supplied 6 pin cable connect the programmer to the ICSP port on your Arduino, making sure you have:
- disconnected your Arduino from USB and any other circuitry.
- correctly identified the polarity and orientation of the programming cable and pin 1 on the ICSP port of the Arduino.
Once you have the cable correctly connected, connect the programmer to usb and the Arduino should power on.
Assuming everything is good to go: open a command prompt, change to the directory you extracted the AVRDUDE software into earlier ("c:\temp\avrdude" for me) and type:
avrdude -p m328p -c usbtiny
See the advanced notes for additional information.
This command should print out something pretty much like this:
AVRDUDE basic output |
If you get this result, add a "-v" to the command:
avrdude -p m328p -c usbtiny -v
which should spew out a whole load of text ending in something that looks like this:
Standard Arduino UNO fuse settings |
What we want to do is to change the value of the lfuse from 0xFF to 0xBF to enable CKOUT.
To verify this, open this awesome AVR fuse calculator in another tab / window and check the lfuse checkbox that reads "Clock output on PORTB0; [CKOUT=0]". You should see the calculated value for lfuse change from 0xFF to 0xBF (and back when you uncheck the option).
Before we proceed any further, a word of caution:
Incorrect fuse settings can brick your Arduino!!!
Some clarification: You need to know that you have a good fuse read at this point. Your values may be different to mine but as long as they are good values you'll be okay.
Thanks to +Al McElmon who reported his hfuse value as D6 not DE. In the fuse calculator you can see that this is because EESAVE has been enabled. This could possibly be a setting on later Arduino Models?
Finally, if everything checks out and you are 100% sure of this, we are one command away from completion:
avrdude -p m328p -c usbtiny -U lfuse:w:0xBF:m -u
This command will write the value 0xBF to the lfuse and set CKOUT.
For a breakdown the "-U" command above, the command:
- selects the lfuse memory for the operation
- writes (use r for read and v for verify)
- the value 0xBF
- in immediate mode (i.e. write the value specified directly)
And there we have it. Your Arduino should now be in a state where we can move onto the more advanced chapters of Matt's book.
Next time we are going to do exactly that, I hope you've enjoyed this post.
Until then, happy hacking!
-(e)
p.s. If you get stuck, I can attempt to help you out, circle me on G+ and send me a message via Messenger, or post a comment and I'll see what I can do.
Advanced Notes:
Perhaps you have a different model of Arduino? (e.g. ATMega168 e.t.c.):
The "-p m328p" switch for AVRDUDE specifies what chip your Arduino has. The "m328p" value is valid for the Arduino UNO and several other models, but will have to be changed for alternative models.
In this case, when using the fuse calculator please input your values for lfuse, hfuse and efuse into the fuse calculator, ensure that you have the correct AVR chip selected and note the change in the lfuse value when CKOUT is selected. The point here is that we wish to change ONLY this value. You can also confirm default board fuse settings in the "boards.txt" file located in the "hardware\arduino" directory of the Arduino IDE installation.
AVRDUDE has many other switches and supports many other programmers. I would suggest that you check out the command line in the documentation.
Sunday, June 10, 2012
Implementing Artcfox's TLC5940 code on an Arduino, Part 1
In a previous post I explained how to port Matt Pandina's TLC5940 library to work with an Arduino.
While that post would allow you to port the code and flash it to an Arduino I didn't go into detail on getting the code to work in an actual circuit.
+Al McElmon prompted me to get my arse into gear and so:
Over the next couple of posts I'm going to do exactly that by referring to some of the chapters and code from Matt's book and providing code and schematics that should build working examples.
This first post will focus on Chapter 3. Lets kick off with a wiring diagram:
As far as the code goes, I have used the code from Chapter3 in the zip file that can be found on Matt's site
You will need to create:
In a future post I will look into some more exciting code, re-programming the fuses on the Arduino to enable the clock output and other bits necessary in order to get Matt's full library working.
Until then, happy hacking!
-(e)
+Al McElmon prompted me to get my arse into gear and so:
Over the next couple of posts I'm going to do exactly that by referring to some of the chapters and code from Matt's book and providing code and schematics that should build working examples.
This first post will focus on Chapter 3. Lets kick off with a wiring diagram:
As far as the code goes, I have used the code from Chapter3 in the zip file that can be found on Matt's site
You will need to create:
- An Arduino project file (.ino for the Arduino IDE 1.0+) with the following contents:
extern "C" { #include "main.h" } void setup() { } void loop() { themain(); }
- Create the following main.h file:
#ifndef __MAIN_H #define __MAIN_H #define PB0 PINB0 #define PB1 PINB1 #define PB2 PINB2 #define PB3 PINB3 #define PB5 PINB5 #define PC0 PINC0 #define PC1 PINC1 #define PC2 PINC3 #define PD1 PIND1 #define PD3 PIND3 #define PD4 PIND4 #define PD5 PIND5 #define PD6 PIND6 #define PD7 PIND7 int themain(void); #endif
- Copy the main.c from the "/code/ch3" dir in Matt's source archive.
- Edit the main.c file to add #include "main.h" after the first two includes:
#include <stdint.h> #include <avr/io.h> #include "main.h"
- And finally rename the function "int main(void)" to "int themain(void)"
In a future post I will look into some more exciting code, re-programming the fuses on the Arduino to enable the clock output and other bits necessary in order to get Matt's full library working.
Until then, happy hacking!
-(e)
Friday, April 20, 2012
More on the AIR 3.2 orientation bug(s)
Back again with another fix...
In my last post Fixing the fullscreen orientation bug in AIR 3.x I mentioned how to fix the fullscreen AIR issue when changing orientation.
What has now come to light is that while that issue is fixed, there are still issues with orientation changes.
The problem I found is that an orientation change from portrait to landscape works, but orientation back to portrait fails indeterminately: sometimes the app would re-orient and sometimes not.
After a significant amount of research I discovered that a missing value in the android:configChanges attribute on the main Activity seems to be the cause of this.
From Android 3.2 an additional value: "screenSize" is available and should be responded to if your are handling config changes yourself with respect to screen orientation.
To fix this, follow the steps in the previous post but also change the android:configChanges attribute to:
Additionally it seems that APKTool can be unreliable in repacking the APK.
A work around for this follows:
This will preserve all resources, effectively just swapping out the manifest.
These fixes seems to have reliably solved the orientation bugs.
In my last post Fixing the fullscreen orientation bug in AIR 3.x I mentioned how to fix the fullscreen AIR issue when changing orientation.
What has now come to light is that while that issue is fixed, there are still issues with orientation changes.
The problem I found is that an orientation change from portrait to landscape works, but orientation back to portrait fails indeterminately: sometimes the app would re-orient and sometimes not.
After a significant amount of research I discovered that a missing value in the android:configChanges attribute on the main Activity seems to be the cause of this.
From Android 3.2 an additional value: "screenSize" is available and should be responded to if your are handling config changes yourself with respect to screen orientation.
To fix this, follow the steps in the previous post but also change the android:configChanges attribute to:
android:configChanges="keyboardHidden|orientation|screenSize"
Additionally it seems that APKTool can be unreliable in repacking the APK.
A work around for this follows:
- Unpack using APKTool.
- Make appropriate manifest changes.
- Re-pack to a temporary apk.
- Remove the AndroidManifest.xml from your original APK.
- Remove the contents of the root/META-INF folder from your original APK.
- Extract the fixed AndroidManifest.xml from the re-packed APK and add it to the root of the original APK.
- Re-sign the original APK as per the previous post.
This will preserve all resources, effectively just swapping out the manifest.
These fixes seems to have reliably solved the orientation bugs.
Thursday, April 5, 2012
Fixing the fullscreen orientation bug in AIR 3.x
EDIT: Please see important information about jarsigner parameters below:
In my day job I lead a team that develops Android AIR applications built on the Adobe AIR runtime.
Recently Adobe have released version 3.2 of AIR for Android that brings many new exciting features (including hardware accelerated rendering) and we were keen to take advantage of these features. We were also keen to use a feature called "Captive Runtime" where the AIR runtime can be packaged with the APK file.
Our application is a full screen app and uses both landscape and portrait orientations and this is where our troubles began.
When running without the Captive Runtime on AIR 3.1 everything worked as expected, however when the captive runtime was included and the app switched orientation the Android title bar appeared. Things got worse with AIR 3.2 as the title bar appeared in both cases. Its important to note that this only seems to occur on ICS.
After an immense amount of spelunking deep into the AIR runtime support code with smali and various other tools (of which I will spare the details) I came to the conclusion that the orientation code is broken with respect to full screen and themes on ICS.
This seems to be as a result of the application of the activity theme as defined in the AndroidManifest file.
The FlashBuilder generated entry should look something like this:
Unfortunately when applied this will cause the title bar to appear.
Luckily there seems to be an easy to implement fix for this behaviour that does not require byte patching of the dex file.
To do this you will need to edit the AndroidManifest.xml and change the theme of the main activity to this:
The AndroidManifest.xml file in the APK is a binary XML file, so the APK needs to be unpacked, fixed, repacked and then finally re-signed.
The tools to accomplish this are apktool and jarsigner.
apktool
apktool can be found at: http://code.google.com/p/android-apktool/
You will need both the windows package and the actual apktool JAR file.
As of this post these are:
apktool-install-windows-r04-brut1.tar.bz2
apktool1.4.3.tar.bz2
Unpack both of these into the same directory.
To unpack an APK you would use the following command:
This will unpack the APK into a directory of the same name as the APK e.g. apk_filename
At this point you should be able to edit the AndroidManifest.xml file and make the changes described above.
To repack the APK:
You may want to use the -f force flag to ensure that the APK is repacked.
jarsigner
jarsigner can be found in the java JDK and it is imperative that you have at least the 1.6+ JDK installed.
To resign an APK using a PKCS12 certificate (.p12 file) you would use the following command:
Please note the addition of the -digestalg SHA1 and -sigalg MD5withRSA parameters. These are essential to correctly sign the APK.
The “1” indicates the alias which is the first cert in the PKCS file. This can be verified by running the keytool application (which is also available in the JDK):
Arguably the theme attribute could be applied at the application node and removed from the activity node. I haven't tested this (it does seem that the activity node theme overrides the application theme).
I hope this helps anyone out there with the same issue.
In my day job I lead a team that develops Android AIR applications built on the Adobe AIR runtime.
Recently Adobe have released version 3.2 of AIR for Android that brings many new exciting features (including hardware accelerated rendering) and we were keen to take advantage of these features. We were also keen to use a feature called "Captive Runtime" where the AIR runtime can be packaged with the APK file.
Our application is a full screen app and uses both landscape and portrait orientations and this is where our troubles began.
When running without the Captive Runtime on AIR 3.1 everything worked as expected, however when the captive runtime was included and the app switched orientation the Android title bar appeared. Things got worse with AIR 3.2 as the title bar appeared in both cases. Its important to note that this only seems to occur on ICS.
After an immense amount of spelunking deep into the AIR runtime support code with smali and various other tools (of which I will spare the details) I came to the conclusion that the orientation code is broken with respect to full screen and themes on ICS.
This seems to be as a result of the application of the activity theme as defined in the AndroidManifest file.
The FlashBuilder generated entry should look something like this:
<activity theme="@style/Theme.NoShadow" ... />
Unfortunately when applied this will cause the title bar to appear.
Luckily there seems to be an easy to implement fix for this behaviour that does not require byte patching of the dex file.
To do this you will need to edit the AndroidManifest.xml and change the theme of the main activity to this:
<activity theme="@android:style/Theme.NoTitleBar.Fullscreen" ... />
The AndroidManifest.xml file in the APK is a binary XML file, so the APK needs to be unpacked, fixed, repacked and then finally re-signed.
The tools to accomplish this are apktool and jarsigner.
apktool
apktool can be found at: http://code.google.com/p/android-apktool/
You will need both the windows package and the actual apktool JAR file.
As of this post these are:
apktool-install-windows-r04-brut1.tar.bz2
apktool1.4.3.tar.bz2
Unpack both of these into the same directory.
To unpack an APK you would use the following command:
apktool.bat d apk_filename.apk
This will unpack the APK into a directory of the same name as the APK e.g. apk_filename
At this point you should be able to edit the AndroidManifest.xml file and make the changes described above.
To repack the APK:
apktool.bat b unpacked_apk_directory new_apk_filename.apk
You may want to use the -f force flag to ensure that the APK is repacked.
jarsigner
jarsigner can be found in the java JDK and it is imperative that you have at least the 1.6+ JDK installed.
To resign an APK using a PKCS12 certificate (.p12 file) you would use the following command:
jarsigner.exe -storetype pkcs12 -keystore pkcs12_file_name.p12 -digestalg SHA1 -sigalg MD5withRSA new_apk_filename.apk "1"
Please note the addition of the -digestalg SHA1 and -sigalg MD5withRSA parameters. These are essential to correctly sign the APK.
The “1” indicates the alias which is the first cert in the PKCS file. This can be verified by running the keytool application (which is also available in the JDK):
keytool.exe -list -v -storetype pkcs12 -keystore pkcs12_file_name.p12
Arguably the theme attribute could be applied at the application node and removed from the activity node. I haven't tested this (it does seem that the activity node theme overrides the application theme).
I hope this helps anyone out there with the same issue.
Wednesday, February 29, 2012
Artcfox's awesome TLC5940 lib and the Arduino IDE
Artcfox has released an absolutely brilliant library and book (!) on how to get an ATMega328 talking to a TLC5940 chip: Demystifying the TLC5940
If you want to control lots of LEDS (RGB or otherwise) the TLC5940 is your chip, unfortunately it has a somewhat complex interface. The TLC5940 is pretty ubiquitous in the Arduino world, but Arctfox (being the hardcore kind of guy he is), wrote his library in pure AVR C.
This does not play well with the Arduino IDE. So for those of you out there that would like to have the ease of use of the IDE and get access to this awesome code, I've done the hard work for you. Here is a breakdown of what is required.
First off some background. I am using the example code from chapter 9 of the source zip.
This is a full example including the library and a test program.
To convert the code we need to understand some things about compiling in the IDE:
And there you have it! Using these techniques I have built an entire firmware and they can be applied to many C libraries out there. The ease of the Arduino IDE as a compiler and uploader can help lower complexity barriers in developing your code.
Hopes this help you out there in Arduino land!
-(e)
If you want to control lots of LEDS (RGB or otherwise) the TLC5940 is your chip, unfortunately it has a somewhat complex interface. The TLC5940 is pretty ubiquitous in the Arduino world, but Arctfox (being the hardcore kind of guy he is), wrote his library in pure AVR C.
This does not play well with the Arduino IDE. So for those of you out there that would like to have the ease of use of the IDE and get access to this awesome code, I've done the hard work for you. Here is a breakdown of what is required.
First off some background. I am using the example code from chapter 9 of the source zip.
This is a full example including the library and a test program.
To convert the code we need to understand some things about compiling in the IDE:
- The example contains a main.c file and in this file is defined the program entry point:
int main(void)
We need to expose this function to the IDE so that we can call the example code. In order to avoid conflicts, we need to rename it to something other than main (the Arduino sketch has a hidden main function that calls setup() and loop()). So we name it something creative like:int themain(void)
- Now we need to define this function in a header so it can be shared with the sketch. To accomplish this, create a main.h file with these contents:
#ifndef __MAIN_H
#define __MAIN_H
int themain(void);
#endif - To include and correctly link to the C function, declare this at the top of your sketch:
extern "C"
This tells the compiler to include the header as a C header and to expect function names defined in the header to be in a C linker format.
{
#include "themain.h"
} - The IDE does not support C99 mode, this means that code like this:
for( int i = 0; i < 10; i++ )
will not compile. The declaration of the variable in the for loop is not allowed and needs to be changed to:int i;
There are a few places in the code where this occurs, fixing this is left as an exercise for the reader... :) The IDE should quickly point out these issues!
for( i = 0; i < 10; i++ ) - Now all we have to do is get the #defines correct so that the code will compile and be configured correctly. This gets interesting. Artcfox has used some makefile ninja wizardry to accomplish this which I have converted into a helper header called "ifdefs.h". This header needs to be included at the top of the "tlc5940.h" file after the #include <avr/io.h> line:
#pragma once
This file (which is basically a port of the makefile to header definitions) looks like this:
#include <stdint.h>
#include <avr/io.h>
#include "ifdefs.h"#define PB1 PINB1
#define PB2 PINB2
#define PB3 PINB3
#define PB5 PINB5
#define PC0 PINC0
#define PC1 PINC1
#define PC2 PINC3
#define PD1 PIND1
#define PD3 PIND3
#define PD4 PIND4
#define PD5 PIND5
#define PD6 PIND6
#define PD7 PIND7
// Defines the number of TLC5940 chips that are connected in series
#define TLC5940_N 4
// Flag for including functions for manually setting the dot correction
// 0 = Do not include dot correction features (generates smaller code)
// 1 = Include dot correction features (will still read from EEPROM by default)
#define TLC5940_INCLUDE_DC_FUNCS 1
// Flag for including efficient functions for setting the grayscale
// and possibly dot correction values of four channels at once.
// 0 = Do not include functions for ganging outputs in groups of four
// 1 = Include functions for ganging outputs in groups of four
// Note: Any number of outputs can be ganged together at any time by simply
// connecting them together. These function only provide a more efficient
// way of setting the values if outputs 0-3, 4-7, 8-11, 12-15, ... are
// connected together
#define TLC5940_INCLUDE_SET4_FUNCS 0
// Flag for including a default implementation of the TIMER0_COMPA_vect ISR
// 0 = For advanced users only! Only choose this if you want to override the
// default implementation of the ISR(TIMER0_COMPA_vect) with your own custom
// implemetation inside main.c
// 1 = Most users should use this setting. Use the default implementation of the
// TIMER0_COMPA_vect ISR as defined in tlc5940.c
#define TLC5940_INCLUDE_DEFAULT_ISR 1
// Flag for including a gamma correction table stored in the flash memory. When
// driving LEDs, it is helpful to use the full 12-bits of PWM the TLC5940 offers
// to output a 12-bit gamma-corrected value derived from an 8-bit value, since
// the human eye has a non-linear perception of brightness.
//
// For example, calling:
// TLC5940_SetGS(0, 2047);
// will not make the LED appear half as bright as calling:
// TLC5940_SetGS(0, 4095);
// However, calling:
// TLC5940_SetGS(0, pgm_read_word(&TLC5940_GammaCorrect[127]));
// will make the LED appear half as bright as calling:
// TLC5940_SetGS(0, pgm_read_word(&TLC5940_GammaCorrect[255]));
//
// 0 = Do not store a gamma correction table in flash memory
// 1 = Stores a gamma correction table in flash memory
#define TLC5940_INCLUDE_GAMMA_CORRECT 1
// Flag for forced inlining of the SetGS, SetAllGS, and Set4GS functions.
// 0 = Do not force inline the calls to Set*GS family of functions.
// 1 = Force all calls to the Set*GS family of functions to be inlined. Use this
// option if execution speed is critical, possibly at the expense of program
// size, although I have found that forcing these calls to be inlined often
// results in both smaller and faster code.
#define TLC5940_INLINE_SETGS_FUNCS 1
// Flag to enable multiplexing. This can be used to drive both common cathode
// (preferred), or common anode RGB LEDs, or even single-color LEDs. Use a
// P-Channel MOSFET such as an IRF9520 for each row to be multiplexed.
// 0 = Disable multiplexing; library functions as normal.
// 1 = Enable multiplexing; The gsData array will become two-dimensional, and
// functions in the Set*GS family require another argument which corresponds
// to the multiplexed row they operate on.
#define TLC5940_ENABLE_MULTIPLEXING 1
// The following option only applies if TLC5940_ENABLE_MULTIPLEXING = 1
#if TLC5940_ENABLE_MULTIPLEXING == 1
// Defines the number of rows to be multiplexed.
// Note: Without writing a custom ISR, that can toggle pins from multiple PORT
// registers, the maximum number of rows that can be multiplexed is eight.
// This option is ignored if TLC5940_ENABLE_MULTIPLEXING = 0
#define TLC5940_MULTIPLEX_N 3
#endif
// Flag to use the USART in MSPIM mode, rather than use the SPI Master bus to
// communicate with the TLC5940. One major advantage of using the USART in MSPIM
// mode is that the transmit register is double-buffered, so you can send data
// to the TLC5940 much faster. Refer to schematics ending in _usart_mspim for
// details on how to connect the hardware before enabling this mode.
// 0 = Use normal SPI Master mode to communicate with TLC5940 (slower)
// 1 = Use the USART in double-buffered MSPIM mode to communicate with the
// TLC5940 (faster, but requires the use of different hardware pins)
// WARNING: Before you enable this option, you must wire the chip up differently!
#define TLC5940_USART_MSPIM 1
// Defines the number of bits used to define a single PWM cycle. The default
// is 12, but it may be lowered to achieve faster refreshes, at the expense
// of the ISR being called more frequently. If TLC5940_INCLUDE_GAMMA_CORRECT = 1
// then changing TLC5940_PWM_BITS will automatically rescale the gamma correction
// table to use the appropriate maximum value, at the expense of precision.
// 12 = Normal 12-bit PWM mode. Possible output values between 0-4095
// 11 = 11-bit PWM mode. Possible output values between 0-2047
// 10 = 10-bit PWM mode. Possible output values between 0-1023
// 9 = 9-bit PWM mode. Possible output values between 0-511
// 8 = 8-bit PWM mode. Possible output values between 0-255
// Note: Lowering this value will decrease the amount of time you have in the
// ISR to send the TLC5940 updated values, potentially limiting the
// number of devices you can connect in series, and it will decrease the
// number of cycles available to main(), since the ISR will be called
// more often. Lowering this value will however, reduce flickering and
// will allow for much quicker updates.
#define TLC5940_PWM_BITS 12
// Determines whether or not GPIOR0 is used to store flags. This special-purpose
// register is designed to store bit flags, as it can set, clear or test a
// single bit in only 2 clock cycles.
//
// Note: If enabled, you must make sure that the flag bits assigned below do not
// conflict with any other GPIOR0 flag bits your application might use.
#define TLC5940_USE_GPIOR0 1
// GPIOR0 flag bits used
#if TLC5940_USE_GPIOR0 == 1
#define TLC5940_FLAG_GS_UPDATE 0
#define TLC5940_FLAG_XLAT_NEEDS_PULSE 1
#endif
// BLANK is only configurable if the TLC5940 is using the USART in MSPIM mode
#if TLC5940_USART_MSPIM == 1
#define BLANK_DDR DDRD
#define BLANK_PORT PORTD
#define BLANK_PIN PD6
#endif
// DDR, PORT, and PIN connected to DCPRG
#define DCPRG_DDR DDRD
#define DCPRG_PORT PORTD
// DCPRG is always configurable, but the default pin needs to change if
// the TLC5940 is using USART MSPIM mode, because PD4 is needed for XCK
#if TLC5940_USART_MSPIM == 1
#define DCPRG_PIN PD3
#else
#define DCPRG_PIN PD4
#endif
// DDR, PORT, and PIN connected to VPRG
#define VPRG_DDR DDRD
#define VPRG_PORT PORTD
#define VPRG_PIN PD7
// DDR, PORT, and PIN connected to XLAT
#if TLC5940_USART_MSPIM == 1
#define XLAT_DDR DDRD
#define XLAT_PORT PORTD
#define XLAT_PIN PD5
#else
#define XLAT_DDR DDRB
#define XLAT_PORT PORTB
#define XLAT_PIN PB1
#endif
// The following options only apply if TLC5940_ENABLE_MULTIPLEXING = 1
#if TLC5940_ENABLE_MULTIPLEXING == 1
// DDR, PORT, and PIN registers used for driving the multiplexing IRF9520 MOSFETs
// Note: All pins used for multiplexing must share the same DDR, PORT, and PIN
// registers. These options are ignored if TLC5940_ENABLE_MULTIPLEXING = 0
#define MULTIPLEX_DDR DDRC
#define MULTIPLEX_PORT PORTC
#define MULTIPLEX_PIN PINC
// List of PIN names of pins that are connected to the multiplexing IRF9520
// MOSFETs. You can define up to eight unless you use a custom ISR that can
// toggle PINs on multiple PORTs.
// Note: All pins used for multiplexing must share the same DDR, PORT, and PIN
// registers. These options are ignored if TLC5940_ENABLE_MULTIPLEXING = 0
// Also: If you add any pins here, do not forget to add those variables to the
// MULTIPLEXING_DEFINES flag below!
#define R_PIN PC0
#define G_PIN PC1
#define B_PIN PC2
#endif
// ---------- End TLC5940 Configuration Section ---------- - Now all that is left to do is round out the sketch:
extern "C"
{
#include "main.h"
}
void setup()
{
}
void loop()
{
themain();
}
And there you have it! Using these techniques I have built an entire firmware and they can be applied to many C libraries out there. The ease of the Arduino IDE as a compiler and uploader can help lower complexity barriers in developing your code.
Hopes this help you out there in Arduino land!
-(e)