2020-2021 ICS4U: Dolgin Development Platform (DDP with DDBv6) |
What is truly unique about our ACES program is that much of the curriculum we explore is based on tools developed within RSGC by those students that have left their talents as gifts for you to benefit from. To begin to appreciate the significance of this, you are encouraged to read the history of this particular platform and the history of our program and philosophy, in general.
With each iteration of ICS4U new insights and opportunities present themselves that compel us to dig deeper. The DDBv6 is your starting point and it is your teacher's hope that, through our combined efforts and achievements, next year's ICS4U group will be looking at Version 8 (Version 7 is in development).
2020-2021 DDP Task Sequence
1. DDBv6: Device Assembly
Your first (pleasant) task is to prepare the hardware and software environments for the Dolgin Development Platform (DDP). On the hardware side assemble your Dolgin Development Board Version 6 (DDBv6) using the parts supplied to you. See the full Parts Table below, right. Joseph V. is deserving of special mention for supplying the 3D printed cases for the DDBv? based on Josh's design.
In our first class of Session 5.1 (January 18) we'll go over specific soldering tips and reminders for the DDBv6. Be sure to listen carefully as replacement parts are obviously difficult to address under current conditions.
On the software side, within the Arduino IDE, under Tools > Board > Boards Manager, be sure to have installed the latest ATtinyCore library by Spence Konde. You may wish to create a DDP folder within your Sketch folder area to hold this device's future software investigations.
2. DDBv6: In-System Programming
With your DDBv6 physically assembled, we are now ready to begin exploiting its capabilities. Whereas the Arduino platform has onboard USB to Serial support, our leaner DDBv6 relies on ISP programming. For this, you'll use your handy Sparkfun AVR Pocket Programmer, inserting the ISP cable into the undermounted 2×3 Shrouded ISP Header (Wurth) connector. Whereas this is a familiar and efficient means to reprogram our AVR MCUs, it does come with a significant downside as the SCK, MISO, and MOSI (PORTA4:6) pins are required to perform the reflashing. Should DDBv7 be entertained by one of you, developing a USB-to Serial programing solution, requiring only TX and RX (PORTB0:1), combined with some SMD components, would be a significant improvement.
Another design feature of the DDBv6 is that once your project is functioning, you can remove the ISP connection, detach the programmer section (pictured to the right) and simply insert its power cable into the USB MINI B Connector (Molex) connector on top to power your prototype. Very convenient (it's likely clear to you by now that the DDBv6's access point design decisions that you've encountered already were purposely intended to maintain low headroom on the top of the platform. Hence, you'll have unobstructed access to the ATtiny84's header pins).
A third power solution is the use of a 9V AC/DC Adapter with a 2.1 mm barrel jack. Again, undermounted through the 2.1 mm Power Jack (Schurter), this strategy offers the best solution for maximum power as it is not restricted to the ~400 mA current limitations associated with your computers' USB ports.
3. DDBv6: The OnBoard LED
Following the lead of Arduino boards, the DDBv6 was designed with an onboard LED tied to digital pin 8 (PORTB.2). For your first series of DDBv6 sketches you are asked to put this LED through its register-level coding paces.
Task.
4. DDBv6: The DDBv6XX.h Library
In programming for the ATmega328P (either the UNO or Nano) you became familiar with predefined constants such as, LED_BUILTIN. Tucked deep inside your Arduino IDE's installation is a library file, called variant.h, that contain this statement (and numerous others),
#define LED_BUILTIN 13
Libraries are an integral part of the development cycle as they reduce development time and ensure greater code accuracy. It would be both instructive and efficient for you to begin to assemble reusable software assets inside your own library of support resources for the DDBv6. Since this is would be a separate file from your specific project applications, you'll need to remember to attach at least two code files when submitting for assessment. Furthermore, since I would have to distinguish between each of your libraries, I would ask that you name your library, DDBv6XX.h where XX are your initials.
Task.
5. DDBv6: Reset Sources
You are familiar with the effect of pressing the Reset button on the UNO or Nano, however further optimization is accessible through a deeper understanding of the subtleties the various Reset sources of AVR MCUs. These sources can be detected and subsequently impact how your code chooses to restart.
Chapter 9 of the ATtiny84 datasheet introduces the concept of System Control and, in particular, the Reset Function. The MCU offers four hardware Reset triggers that include: Power On, External, BrownOut, and Watchdog. At the end of this chapter, there is a description of the Registers that can be inspected and manipulated. For our purposes, we'll limit ourselves to a simple distinction between the Power On and External Reset triggers. Page 41 of the ATtiny84 datasheet presents the MCUSR Register, (see: ATtiny84 Register Summary)
in which the source of a Reset can be identified through the use of flags (bits).
Task.
A solution to the benefit of serial streaming to the Arduino Serial Monitor and Plotter from the DDP comes in the form of a USB to TTL Serial Cable from Adafruit (below, left). The basis for this discovery comes in the form of this instructable from OldArkie in which he describes a similar approach from the ATtiny85. The image below, right (click to enlarge) is of a dynamic application of a thumb joystick in a DDP running a sketch (SerialOutputDDP.ino
) that streams the 2D coordinates to a Processing application (CircularTrigFunctions.pde
) developed to introduce students to the true origin of the six trigonometric functions: The Circular Functions. USB cable connections to the DDP can be determined by looking closely at the photo. The White 5V wire is not connected.
I'll provide a demonstration in class on the resumption of classes after the March Break 2020. Both sketches are available from DDP's GitHub repository.
Adafruit USB-to-TTL Serial Cable #954 | DDP Control over the Processing Circular Function Sketch |
6. DDBv6: SoftwareSerial
Until such time as the DDB supports hardware USB-to-Serial communication (Version 8?) we make do with software serial support. The USB-TTL Serial cable from Adafruit that you have been provided with permits your DDBv6 to transmit data to your Arduino IDE's Serial Monitor and Plotter.
Task.
#define RXPIN 9
#define TXPIN 10
#include <SoftwareSerial.h>
SoftwareSerial ddbSerial(RXPIN, TXPIN);
Interrupt-driven programming strategies can provide a more efficient approach for responding to asynchronous events. Chapter 10 of the ATtiny84 datasheet, Interrupts, introduces the MCU's Interrupt Vector Table that appears to the right. The order in which they appear in the Table implies priority should multiple events happen simultaneously.
As can be seen, a Reset event is assigned the highest possible precedence, followed by a (single) External Interrupt (INT0; the ATmega328P has two and the ATmega2560 has eight!), and so on. A design mistake I made on the DDBv6 was to attach the onboard LED to digital pin 8 (PB2). Since this is the same pin that supports the INT0 function, the feature was rendered dysfunctional. In DDBv7, the onboard LED was relocated to digital pin 4 (PA4/SCK) restoring the use of INT0.
In class, we'll temporarily switch back to the UNO/Nano and confirm your register-level coding of its INT0 or INT1 interrupt capability through the use of the debouncer. We'll be sure to make maximum use of the 328P's header file of predefines: iom328p.h. Also, since the Arduino IDE employs the avr-gcc compiler, the 328Ps Interrupt Service Routines (ISRs) use the following Vector Table syntax for naming the ISRs,
Page 71 of the ATmega328P datasheet provides Register level details associated with the ATmega328P's External Interrupt manipulation.
7. DDBv6: Pin Change Interrupt
Chapter 11 of the ATtiny84 datasheet discusses this MCU's functionality with respect to external Pin Change interrupts. Whereas specific bits can be configured for 'sense control' on the single External Interrupt INT0 (PORT B.2) to sense rising, falling, change, or low signal conditions, only change triggers a Pin Change Interrupt. However, the good news is that any digital pin can be conditioned as such. The applicable registers, bits, and flags are summarized below.
Task.
8. DDBv6: Morland Bargraph v3
With register-level coding skills and a custom DDBv6 library underway we can turn to a familiar friend to strengthen our command of these skills in the efficient manipulation of port bits to create a dedicated MBShiftOut()
function.
Design Considerations. In designing the MBv3's minimal 6-pin breakout board there simply was no optimum arrangement that enabled it to be a UNO-compatible appliance. Wherever it is placed it puts an unacceptable strain on the port pin forced to serve as the 5V source. So, given the MBv3's versatility in so many ACES' projects, the ATtiny84's pin breakout strategy accommodated an optimal position for the MBv3 on the DDBv6. Click the image to the right to enlarge. The 5V and GND supply pins are positioned correctly to provide the appliance with full power access. The only issue that remains is the non-critical conflict with the onboard LED. This has been addressed in the DDBv7 with its relocation to Pin 4 (PA4/SCK).
Task.
9. DDBv6: Rotary Encoder
As discussed in class, encoders are devices that can map digital signals to binary form. Rotary encoders can present relative changes in angular position to binary form that can be read by MCU to determine counts, or even rotational speed, when applied over the time domain. Here's a short video highlighting the output of an inexpensive rotary encoder on a KY-040 breakout board from Amazon, Rotary Encoder with Bicolor LEDs.
In the Serial Monitor capture to the right, rotary encoder outputs A and B were configured as pin change interrupts on digital pins 4 and 5 (PD4..5), respectively. The port PIND was read and echoed after one clockwise rotation between detente positions followed by one counterclockwise rotation. The Gray Code sequence is clear as should be the strategy to detect the angular direction.
Task.
10. DDBv6: CharlieStick
#define
compiler directives that provide aliases for the specific AVR MCU registers and bit-within-a-byte numbers.#define
s from the header file to have your SimonStick function as a VU meter for the TMP36 temperature sensor.Theory | JLC Rendering |
---|---|
0xFF
and demonstrate a 'breathing' bargraph by placing a signal on the 595's output enable pinmap()
and constrain()
are handy functions for this application as is bit-shifting).Finally, pack these four Morland Bargraph exercises into a single sketch with some strong code design decisions. Note, the mark you will receive will be based, in part, on how unique your code is from that of your peers.
11. DDBv6: Power Management
The ATtiny84's Interrupt Vector Table continues to serve as a guide to strengthening your hardware, software, and design skill base. Next stop: Watchdog time-out interrupt support for the power-down sleep mode.
As a context, it is not difficult to imagine a remotely-situated, solar-powered, MCU-based sensor device that collects (and possibly transmits) data to a centralized location. Understandably, optimum use of power would contribute to its viability and sustainability. This segment provides some insights into how some aspects of such a prototype could be implemented to conserve power between readings.
One video I encourage you to watch is Kevin Darrah's Low Power Arduino! Deep Sleep Tutorial. This presentation contains applicable material for this investigation.
I've partitioned this investigation into two development stages.
Task.
Dolgin Development Terminology
DDB. The Dolgin Development Board is the assembled PCB that provides ACES with our own MCU-prototyping motherboard based on the ATTiny84, developed by J. Dolgin (ACES ' 20, Waterloo '25) from an earlier concept by J. Corley (ACES '19, Queen's '23).
Appliance. An Appliance is an ACES' term for any PCB-based device that is inserted vertically into a SINGLE female header on either the UNO or the DDP. The Schaffer Traffic Light (STL), the Morland Bargraph (MB) and the CharlieStick, are three previous examples.
Shield. A Shield is the conventional Arduino term for a PCB-based device that spans BOTH female headers, horizontally, on the UNO. ACES have adopted this term in reference to a device that spans both headers on the DDB. In late 2019, two DDP Shields were developed for ACES to continue to develop their MCU prototyping skills. By the end of the term, after working extensively with these two shields, every ICS4U ACE will have the opportunity to add to the inventory of our DDP Shields through the creation of their own, original, Legacy Shield for future ACES to benefit from. As of Spring 2021, the ACES collection has increased to include five shields: Intersection, ADC, Universal 1, Universal 2, and Equalizer.
DDP. The Dolgin Development Platform is the ACES' term for any number of shields stacked on the DDB, installed in our 3D-printed custom base, all functioning as a coordinated unit.
For your first shield exposure our Schaffer Traffic Light (STL) gets a significant upgrade in the form of 2-way Intersection simulation with countdown displays in both directions. The device can be thought of a Finite State Machine (of the Moore variety) in which the state transitions are to be triggered through WDT Interrupts you were acquainted with from a previous section.
DDBv6 | Intersection Shield v2 |
Whereas the Intersection Shield was strictly output only, The ADC Shield , combines input with output exploiting the 10-bit Analog-to-Digital Conversion feature of the ATtiny84 (oddly enough, the DIP14 ATtiny84 offers 8 separate ADC channels as compared to the DIP28 ATmega328P's 6). Developing it to its full potential requires you to revisit familiar Grade 10 hardware, Grade 11 PoV software skills, Grade 12 WDT scheduling and introduces you to the register-level implementation of the ADC capability on the ATtiny84 (among others things :)
I've partitioned this investigation into four development stages.
Task.
#define
the corresponding port/pin usage. Note. When you create your own DDP Legacy Shield do not overlook the benefits of smart silk-screening to those that follow you.
14. DDP: ADC: Successive Approximation
Of all the features that microcontrollers offer, a strong case could be made for Analog to Digital Conversion being its most important function. After all, the ability to capture real world data and digitize it for manipulation, transmission, and storage purposes is an undeniably critical feature within our modern world. Although the AVR line of 8-bit MCUs offers a 10-bit onboard DC unit that we've exploited for a number of purposes, what if our needs called for either a higher or lower sampling accuracy? A deeper understanding of how the ADC function works is called for should we wish to build our own ADC unit.
An informative base from which to mount our investigation might start with a somewhat familiar binary tree. As a child you might have engaged in a guessing game in which a series of ranked guesses with a response of either lower or higher could lead you to your target. Indeed, this approach could lead to a conversion method from decimal to binary as suggested by the labeled paths.
Day 1.
Previous projects over the years have exploited the use of operational amplifiers as comparators. The LM741 and dual LM358 are common examples that two voltage levels on their non-inverting and inverting inputs, outputting a 1 or or 0 depending on whether the non-inverting voltage is greater than the inverting input, and a 0 otherwise. The ATtiny84 has (as other AVR MCUs do) a built in comparator that will provide the foundation for week of ADC/DAC exploration.
TBD...
A quotation, attributed to the Greek statesman, Pericles, is apropos,
"What you leave behind is not what is engraved on stone monuments, but what is woven into the lives of others."
ACES' tradition reflects a popular culture trope in which Master Craftsmen Make Their Own Tools. A quick review of the ACES PCB Archive supports this claim. In this latest attempt to enrich the engineering experience of the ACES that follow, you have the opportunity to add to the inventory of DDP Shields. Coupled with this task is the opportunity to weave your name in the minds of future ACES as Bagga, Benson, Schaffer, Morland, and Dolgin have done in yours.
Task.
SA: Serial Binary Game | PB: Pin Change interrupts | AG: Signal Generator |
LRC: IR Remote | JS: Analog Explorer | JV: Servo Shield |
7. DDP: AVR Assembly Language Programming
7.1 References
7.1.1 GPIO Port Summaries
7.1.1.1 ATtiny84
7.1.1.2 ATmega328P
7.1.2 Summary: AVR Assembly Instruction Set
7.1.3 Detailed: Online AVR Assembly Instruction Set
7.1.4 Full Manual: AVR Assembly Instruction Set
7.2.1 Inline (8-bit) AVR Assembly (within the Arduino IDE)
In our first few AVR assembly exercises you will explore how the AVR-gcc toolchain permits the interspersing of assembly language statements amongst Arduino C statements through the use of the asm ()
macro. This blog offers a primer...The following video provides a good foundation for AVR Assembly concepts in a little more detail than is required at the moment but, nevertheless, is highly instructive: Intro to Arduino Inline Assembly
7.2.1.0. The Fastest! Blink
In a previous exercise you successfully confirmed that setting a bit in an AVR Port's PIN register, toggled the corresponding bit in its PORT register, leading to the fastest way to blink an LED. In this first exercise we'll perform the same task, in assembly language.
Task.
InlineAssembly
folder, create a New Project called BlinkInline
.setup()
function , add an asm volatile ()
macro that declares PORTA, pin 0, for output. loop()
function, add an asm volatile ()
macro that writes 1 to PINA, pin 0.delay()
function add a 1 second delay between loop iterations.7.2.1.1. (All Assembly) Delay
A clock cycle is a tick of the MCU's oscillator. The source of these ticks typically comes from the MCU's external crystal or internal RC clock.
As you can imagine, the benchmark measure of the efficiency of any code sequence rests with determining the number of MCU clock cycles (or simply clocks) it takes to execute, not the absolute amount of time the code takes to execute. Courses in your university Comp. Eng, program will require you to explore this this so let's get a simple taste, now. Further reading: AVR-libc Benchmarks
The delay(ms)
function is handy, but unproductive, as all it does is waste clock cycles. Nevertheless, exploring an 'All AVR Assembly' equivalent to the delay(ms)
function is instructive for our ends. So, although the previous exercise confirmed that inline assembly and high-level C can coexist, this exercise allows you to explore replacing the high-level delay(ms)
function altogether through additional assembly instructions inside our loop()
function's asm volatile( )
macro. In doing so, we'll also acquaint ourselves with a few more AVR instructions.
Task.
sbi
instruction consume in execution?delay(1000)
. Again, choose the avr-gcc syntax for now.BlinkInline
sketch from the previous class and remove the call to the delay(1000)
function. Copy the auto-generated code from the previous step and insert it into your loop()
function's asm volatile( )
macro.
7.2.2 Standalone (8-bit) AVR Assembly Coding (within the Arduino IDE)
Reference (unnecessarily complicated but informative, nonetheless): https://rwf.co/dokuwiki/doku.php?id=smallcpus
The Arduino IDE offers painfully few tools for the aspiring assembly language programmer to develop a skill set but it has one important thing going for it: familiarity. Make no mistake, confidence, coupled with steady productivity and reasonable success, are required to sustain interest in the challenge of low-level coding and, so far, you're making SUBSTANTIAL progress.
So, let's keep the hardware task the same (fastest blink of an LED) but strip away the cumbersome " "
and \n
from inline assembly to write clearer, standalone, AVR assembly code.
Standalone
Assembly
, create a first project called FastestBlink
.FastestBlink.ino
leaving the file completely blank. (an informative action would be to compile (verify) this empty file and read the diagnostic error messages it produces. Remember, all the code you have ever run in the Arduino IDE operates within the C driver shell main.cpp
)setup()
and loop()
function. We'll now provide these functions in Assembly!.S
(Note: it MUST be a capital S). Look to the top right corner of the IDE, click on the dropdown button, select New Tab
and, in the text box, label the new file, asm.S
. (Note: you could call it anything you want but let's keep it consistent for today)asm.S
. file. The .global
assembler directive is one of many that assists the toolchain with the creation of the final executable. Functions in assembly language are simply labels. Furthermore, it should be obvious now that they terminate with a ret
statement..global setup setup: ret .global loop loop: ret
setup
function, free from the " "
and \n
syntax required in inline assembly. Comment appropriately.loop
function. Comment appropriately..global
directive is not required as this function requires only local access (ie, not visible to other files in the project that will be linked together). Return to our AVR Delay Calculator to obtain assembler code for the body of our kill
function that will simply waste 1s worth of clock cycles. Comment appropriately.asm.S
file, upload. and admire!File>Examples>Blink
sketch.7.2.2.2. Schaffer Traffic Light
In this second standalone AVR Assembly exercise we return to the venerable STL to continue to expand our knowledge base of instructions. Setting (or clearing) an individual bit od a PORT is handy, but typically you'll want to affect multiple bits at a time. For these purposes you'll need the in
and out
instructions.
Place your Schaffer's Traffic Light into DDP pins A2..A0 + GND. (conveniently, the Intersection Shield works just as well for these exercises)
7.2.2.1.1 Version 1
AssemblyStandalone
folder create the project STLv1
. STLv1.ino
file and add an STLv1.S
tab..global
functions setup
and loop
.7.2.2.1.2 (Improved) Version 2: AVR Assembly delay(ms) Function
Rather than entering and exiting multiple asm volatile ()
blocks, Version 2 accomplishes the same result with a single asm volatile ()
block by replacing the Arduino C delay(ms)
function with an assembly function that does the same thing (waste clock cycles).
STLv1
project as STLv2
. asm volatile ()
code block in the setup()
function, run the STL continuously for same the 3s-1s-3s delay sequence.
To strengthen your skill set, I have carefully developed an integrated set of increasingly-complex projects based on the DDP and the ADC Shield especially for you; the 2019/2020 ICS4U class. It's imperative that you take the concepts that you have been taught, acquire these skills, and prove to yourself you can handle a degree of complexity.
To start, Using the AVR Assembly knowledge gained so far, in particular our Data and Labels lesson, you are asked to present single digit counting, either on a standalone 7-segment display or, preferably, on your ADC Shield. I have prepared a video of what I expect you to develop:
Seven Segment Counting Support Video
I have broken down the necessary steps below to such a degree that anyone with even the slightest bit of motivation and interest in preparing for the challenges that lay beyond RSGC should be able to fulfill.
Task.
Shiftout7Segment
. .cseg
or .text
), define a 10-element array of segment maps of the form (0Babcdefg0
). This will require the use of the .DB
or .BYTE
directives.PA4
(which is connected to the base pin of its low-side transistor). These assignments can be determined from theADC Shield's silk-screening.Be prepared for Monday in the event you get randomized for a Show&Tell.
This project is a consolidation of previously undertaken AVR skills, investigations, and projects. The first DDP Shield you worked with, the ADC Shield, has a set of four, fully-resisted, 7-segment displays, accessible through the use of the onboard 595 shift register, using a Persistence of Vision (PoV) scheme. The PoV is enabled as the ATtiny84's port pins PA1..PA4
are tied to the respective base pins of the four, low-side NPNs that provide ground access to each of the CC displays, in turn.
Task.
PoVontheADC
. .DB
(.BYTE
) directive, your code should define an 10-element array of segment constants within the .cseg
(.text
) section, defining the state of the LEDs in the order 0Babcdefgx
..db
directive (or .byte
if in the Arduino) to be displayed on the ADC Shield using your shiftout
function from a previous project by the same name. MSBFIRST
if the segments are defined as indicated in the previous step.DATA
, LATCH
, and CLOCK
equates can be found in a recent post to the ICS4U Conference.PA1
through PA4
.Attach JUST two files ONLY: DER.docx and either main.asm (or PoVontheADC.S if you develop within the Arduino IDE) by the deadline.
Pseudocode for this Algorithm...
number
the two-digit value (eg. 99) to be displayednumber
count
to hold the tens digit. Initialize it to 0Z
the address of number
r16
with Z
(number
) with the lpm
instructionr16
count
) advance to Step 10 (brmi
)count
and go back to Step 7count
in the first of two SRAM storage bytes reserved in Step 3 (sts
)r16
(this is the units digit) and store to the second reserved byte in SRAM (sts
)Z
with the starting address of the LUTr16
with the units digits from SRAM (lds
)r16
to ZL
to have it point to the correct segment map in the LUTn
with the value pointed to by Z (lpm)
cbi
) (remember, we need to reduce ghosting)shiftout
functionsbi
)Z
with the starting address of the LUTr16
with the tens digits from SRAM (lds
)r16
to ZL
to have it point to the correct segment map in the LUTn
with the value pointed to by Z (lpm)
cbi
) (remember, we need to reduce ghosting)shiftout
functionsbi
)7.2.2.4. Morland Bargraph Array Presentation
To be developed...
To be developed...
To be developed...
To be developed...
7.3 Standalone Assembly (Atmel Studio 7)
Yikes! :)