{"id":5033,"date":"2024-04-08T19:38:50","date_gmt":"2024-04-08T19:38:50","guid":{"rendered":"https:\/\/a-thousand-projects-staging-2.onyx-sites.io\/?post_type=project&#038;p=5033"},"modified":"2026-05-01T15:26:04","modified_gmt":"2026-05-01T15:26:04","slug":"doceca-timer","status":"publish","type":"project","link":"https:\/\/athousandprojects.com\/staging\/project\/doceca-timer\/","title":{"rendered":"Dodeca Timer"},"content":{"rendered":"<div class=\"et_pb_section_0 et_pb_section et_section_regular et_block_section\">\n<div class=\"et_pb_row_0 et_pb_row et_block_row\">\n<div class=\"et_pb_column_0 et_pb_column et_pb_column_2_5 et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_0 et_pb_image et_pb_module et_flex_module\"><span class=\"et_pb_image_wrap\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2026\/04\/dodeca-feature-image.png\" title=\"dodeca-feature-image\" width=\"300\" height=\"200\" srcset=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2026\/04\/dodeca-feature-image.png 300w\" sizes=\"(max-width: 300px) 100vw, 300px\" class=\"wp-image-9995\" \/><\/span><\/div>\n<\/div>\n\n<div class=\"et_pb_column_1 et_pb_column et_pb_column_3_5 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_0 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h1>Dodeca Timer<\/h1>\n<p>This was the project I did for my final project when competing the \"<a href=\"https:\/\/classpert.com\/classpertx\/courses\/making-embedded-systems\/cohort\">Making Embedded Systems<\/a>\" course by Elecia White.\u00a0<\/p>\n<p>I saw a product that was an interesting concept and thought I would like to make it myself. The idea is to use a Dodecahedron to create a physical way to track time spent during the day. In other words, tracking tasks. Each side of the dodecahedron can be assigned a task such as \u2018Email\u2019, \u2018Coding\u2019, \u2018Lunch\u2019, \u2019meeting\u2019 etc. As you start or stop a task you simply set the Dodecahedron with the task you are about to do facing up.<\/p>\n<p>The system logs the start time, End time (including date) and duration of each task. This data can then be exported via the command terminal. For the initial project, this will be via serial, but in future, this would be via Wifi or Bluetooth to a device or server.<\/p>\n<p>A set of LEDs and sound will be used to attract attention when a task's allotted time is up.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_1 et_pb_row et_block_row\">\n<div class=\"et_pb_column_2 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_1 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2>Features<\/h2>\n<ul>\n<li>12 sided Dodecahedron<\/li>\n<li>Configuration \u2013 Via Command line initially\n<ul>\n<li>Set each face task<\/li>\n<li>Set task min\/ max time<\/li>\n<li>Set End time<\/li>\n<li>Configure and save task configuration to flash.<\/li>\n<\/ul>\n<\/li>\n<li>Each side has RGD lighting to indicate:\n<ul>\n<li>Flash to indicate x number of Mins (not implemented yet)<\/li>\n<li>Task is being timed<\/li>\n<li>Task time has ended<\/li>\n<li>Task has been paused<\/li>\n<\/ul>\n<\/li>\n<li>Speaker to play relevant sounds (mpt implemented yet)\n<ul>\n<li>End of time\/start\/ stop\/pause<\/li>\n<\/ul>\n<\/li>\n<li>Accelerometer &amp; Gyro to determine which side is facing up.<\/li>\n<li>(Button on each side to Pause\/Start)<\/li>\n<li>(Initially \u2013 Radio Comms for Command line - xBee)<\/li>\n<\/ul>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_2 et_pb_row et_block_row\">\n<div class=\"et_pb_column_3 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_2 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2>Future development<\/h2>\n<p>There are a number of ways in which the prototype could be enhanced.<\/p>\n<ol>\n<li>Add WiFi\/Bluetooth for configuration and data retrieval is a must.<\/li>\n<li>Add in the sound module so that alarms and notification can be audible.<\/li>\n<li>Better motion detection so that the processor can be woken up when the device is moved rather than polled. The current Motion Detection will set an interrupt pin when there is movement in the XY plane, but if the accelerometer is angled down then the X &amp; Y planes are always triggered. The unit does not appear to have an interrupt for Gyro movement as this would have suited it better. Ideally I would look for a better module.<\/li>\n<li>Auto switch off with a link to the regulator switch the regulator Enable line<\/li>\n<li>Ability to set alarms for the day<\/li>\n<li>Better power management<\/li>\n<li>Custom designed PCB<\/li>\n<li>Smaller dodecahedron \u2013 made with Perspex\/plastic<\/li>\n<li>Direct data download via USB<\/li>\n<li>Firmware updates<\/li>\n<li>Datastore being saved to flash if power out.<\/li>\n<\/ol>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_3 et_pb_row et_block_row\">\n<div class=\"et_pb_column_4 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_3 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h1>Hardware<\/h1>\n<table border=\"1\" style=\"border-collapse: collapse; width: 100%;\">\n<tbody>\n<tr>\n<td style=\"width: 33.3333%;\"><strong>Name<\/strong><\/td>\n<td style=\"width: 33.3333%;\"><strong>Description<\/strong><\/td>\n<td style=\"width: 33.3333%;\"><strong>Notes<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 33.3333%;\">Processor board<\/td>\n<td style=\"width: 33.3333%;\">Black Pill<br \/>STM32F411CEU6<\/td>\n<td style=\"width: 33.3333%;\">Chosen for small footprint so that it will fit into the dodecahedron. It also has a 32.7K crystal for the RTC and enough peripherals. Memory and features needed for the project.<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 33.3333%;\">Accelerometer and Gyro<\/td>\n<td style=\"width: 33.3333%;\">GY-521<\/td>\n<td style=\"width: 33.3333%;\">The module uses the MPS6050 mems chip.<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 33.3333%;\">Addressable LED\u2019s<\/td>\n<td style=\"width: 33.3333%;\">WS2812<\/td>\n<td style=\"width: 33.3333%;\">Each side will have a 12 LED ring of Addressable LED\u2019s<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 33.3333%;\">Battery Gauge<\/td>\n<td style=\"width: 33.3333%;\">Adafruit fuel gauge<\/td>\n<td style=\"width: 33.3333%;\">\n<p>On Semiconductor LC709203F - Smart LiB Gauge<\/p>\n<p>Battery Fuel Gauge LSI<\/p>\n<p>for 1-Cell Lithium-ion (Li+)<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 33.3333%;\">RF Serial<\/td>\n<td style=\"width: 33.3333%;\">Xbee S2C<\/td>\n<td style=\"width: 33.3333%;\">Used for serial communication. Configured for straight through serial.<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 33.3333%;\"><\/td>\n<td style=\"width: 33.3333%;\"><\/td>\n<td style=\"width: 33.3333%;\"><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_4 et_pb_row et_block_row\">\n<div class=\"et_pb_column_5 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_4 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h3><a name=\"_Toc106031790\"><\/a>Processor Peripherals Used <o:p><\/o:p><\/h3>\n<table border=\"1\" style=\"border-collapse: collapse; width: 100%;\">\n<tbody>\n<tr>\n<td style=\"width: 50%;\"><strong>Name<\/strong><\/td>\n<td style=\"width: 50%;\"><strong>Use<\/strong><\/td>\n<\/tr>\n<tr>\n<td width=\"349\" style=\"width: 50%;\">I2C<\/td>\n<td width=\"349\" style=\"width: 50%;\">Fuel Guage<\/p>\n<p>MPU605 acceleromiter<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td width=\"349\" style=\"width: 50%;\">DMA\/PWM<\/td>\n<td width=\"349\" style=\"width: 50%;\">Addressable LED\u2019s<\/td>\n<\/tr>\n<tr>\n<td width=\"349\" style=\"width: 50%;\">USART<\/td>\n<td width=\"349\" style=\"width: 50%;\">Serial communication via xBee RF module<\/td>\n<\/tr>\n<tr>\n<td width=\"349\" style=\"width: 50%;\">Timer (1)<\/td>\n<td width=\"349\" style=\"width: 50%;\">Used for\u00a0 PWM to drive the LED\u2019s \u2013 Driven by DMA<\/td>\n<\/tr>\n<tr>\n<td width=\"349\" style=\"width: 50%;\">Timer (9)<\/td>\n<td width=\"349\" style=\"width: 50%;\">Used for to wake the device up from sleep.<\/td>\n<\/tr>\n<tr>\n<td width=\"349\" style=\"width: 50%;\">RTC \u2013 real Time Clock<\/td>\n<td width=\"349\" style=\"width: 50%;\">Used for time tracking\/Time stamps<\/td>\n<\/tr>\n<tr>\n<td width=\"349\" style=\"width: 50%;\">CRC<\/td>\n<td width=\"349\" style=\"width: 50%;\">CRC used for Config check<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_5 et_pb_row et_block_row\">\n<div class=\"et_pb_column_6 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_5 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h3>Block Diagrams<\/h3>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_6 et_pb_row et_block_row\">\n<div class=\"et_pb_column_7 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_1 et_pb_image et_pb_module et_flex_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/04\/Hardware-Block-Diagram.png\" title=\"Hardware Block Diagram\" class=\"wp-image-5143\" \/><\/span><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_7 et_pb_row et_block_row\">\n<div class=\"et_pb_column_8 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_2 et_pb_image et_pb_module et_flex_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/04\/Software-Block-Diagram.png\" title=\"Software Block Diagram\" class=\"wp-image-5145\" \/><\/span><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_8 et_pb_row et_block_row\">\n<div class=\"et_pb_column_9 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_3 et_pb_image et_pb_module et_flex_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/04\/Software-Hierarchy-Diagram.png\" title=\"Software Hierarchy Diagram\" class=\"wp-image-5147\" \/><\/span><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_9 et_pb_row et_block_row\">\n<div class=\"et_pb_column_10 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_6 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h1>Hardware Description<\/h1>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_10 et_pb_row et_block_row\">\n<div class=\"et_pb_column_11 et_pb_column et_pb_column_2_5 et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_4 et_pb_image et_pb_module et_flex_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/04\/BlackPill.png\" title=\"BlackPill\" class=\"wp-image-5157\" \/><\/span><\/div>\n<\/div>\n\n<div class=\"et_pb_column_12 et_pb_column et_pb_column_3_5 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_7 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p>The \u2018Black Pill\u2019 processor, \u00a0developed by <a href=\"https:\/\/github.com\/WeActTC\/WeAct-Studio-Product\">WeAct \u00a0Studio<\/a>, \u00a0was used in this project due to the ample peripherals, clock speed and Flash\/Ram configuration. All allowing for more than enough program and memory space which allows for expansion.<\/p>\n<p>The specific board uses the STM32F411CEU6.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_11 et_pb_row et_block_row\">\n<div class=\"et_pb_column_13 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_8 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2>Processor Specifications<\/h2>\n<table border=\"1\" style=\"border-collapse: collapse; width: 100%;\">\n<tbody>\n<tr>\n<td width=\"200\" style=\"width: 49.8525%;\">Clock<\/td>\n<td width=\"200\" style=\"width: 50.1475%;\">100Mkz<\/td>\n<\/tr>\n<tr>\n<td width=\"200\" style=\"width: 49.8525%;\">Flash<\/td>\n<td width=\"200\" style=\"width: 50.1475%;\">512K<\/td>\n<\/tr>\n<tr>\n<td width=\"200\" style=\"width: 49.8525%;\">Ram<\/td>\n<td width=\"200\" style=\"width: 50.1475%;\">128K<\/td>\n<\/tr>\n<tr>\n<td width=\"200\" style=\"width: 49.8525%;\">Cortex M4<\/td>\n<td width=\"200\" style=\"width: 50.1475%;\"><\/td>\n<\/tr>\n<tr>\n<td width=\"200\" style=\"width: 49.8525%;\">Peripherals<\/td>\n<td width=\"200\" style=\"width: 50.1475%;\">\n<p>ACD x 1<\/p>\n<p>RTC x 1<\/p>\n<p>Timers x 8<\/p>\n<p>UARTS<\/p>\n<p>I2C x 3<\/p>\n<p>SDIO x 1<\/p>\n<p>SPI x 5<\/p>\n<p>USART x 3<\/p>\n<p>USB_OTG_FS<br \/>I2S x 5<\/p>\n<p>CRC<\/p>\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2><strong>Peripherals used<\/strong><\/h2>\n<ul>\n<li>RTC for time keeping and alarms<\/li>\n<li>Timer 9 for sleep wake up in interrupt<\/li>\n<li>UART for xBee serial communication via RF<\/li>\n<li>CRC \u2013 for configuration Checksum<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>The Dev board has the following Specifications<\/p>\n<table border=\"1\" style=\"border-collapse: collapse; width: 100%;\">\n<tbody>\n<tr>\n<td width=\"301\" style=\"width: 49.8525%;\">\n<p>HSE external crystal<\/p>\n<\/td>\n<td width=\"301\" style=\"width: 50.1475%;\">\n<p>25 Mhz<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td width=\"301\" style=\"width: 49.8525%;\">\n<p>LSE<\/p>\n<\/td>\n<td width=\"301\" style=\"width: 50.1475%;\">\n<p>32.768kHz<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td width=\"301\" style=\"width: 49.8525%;\">\n<p>LDO regulator for 5V input<\/p>\n<\/td>\n<td width=\"301\" style=\"width: 50.1475%;\">\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td width=\"301\" style=\"width: 49.8525%;\">\n<p>USB-C<\/p>\n<\/td>\n<td width=\"301\" style=\"width: 50.1475%;\">\n<p>&nbsp;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td width=\"301\" style=\"width: 49.8525%;\">\n<p>Buttons<\/p>\n<\/td>\n<td width=\"301\" style=\"width: 50.1475%;\">\n<p>User Key<br \/>BOOT<br \/>Reset<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_12 et_pb_row et_block_row\">\n<div class=\"et_pb_column_14 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_9 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2>External Hardware<\/h2>\n<h3><a name=\"_Toc106031796\"><\/a>Accelerometer\/ Gyro<\/h3>\n<p>The heart of the project is the detection of the orientation of the dodecahedron linked with the real time logging. The system will need to detect which side of the dodecahedron is facing up and detect a change. The system detects between the specific orientation change and ignores any other movement to cater for the device being moved around the work area or bumped.<\/p>\n<p>The module being used is the GY-521 module which uses the MPU-6050 3 Axis Gyroscope\/Accelerometer chip<\/p>\n<h3><a name=\"_Toc106031797\"><\/a>RF Serial Module \u2013 Xbee S2C<\/h3>\n<p>The Xbee is used to transfer serial data via RF. The Dodec Timer cannot have cabled attached and need to be untethered from the PC.<\/p>\n<p>The PAN ID\u2019s and serial configuaration were set up manually via the Digi International configuration software called XCTU.<\/p>\n<p>For the purposes of this project, I did not add in Xbee configuration from the device as only one was being made, however, the configuration of the module is easy with simple AT command via serial.<\/p>\n<p>The Xbee radio uses TTL UART for communication protocol to the SMT32.<\/p>\n<h3><a name=\"_Toc106031798\"><\/a>I2S Audio Amp \u2013 Not implemented as yet<\/h3>\n<p>A small Audio amp module using the I2S communication protocol is used for various alerts. These will be small sound bytes in the form of pleasant beeps or tones.<\/p>\n<p>The module is a Max98357A driver from Adafruit (<a href=\"https:\/\/www.adafruit.com\/product\/3006\">https:\/\/www.adafruit.com\/product\/3006<\/a>)<\/p>\n<h3><a name=\"_Toc106031799\"><\/a>LED<\/h3>\n<p>Each side of the dodecahedron has a ring of 12 addressable LED\u2019s. The face up LED\u2019s indicate the following<\/p>\n<p>The LED ring is a 12 LED 50mm ring using \u00a0WS2812B LED\u2019s.<\/p>\n<p>The brightness is kept to approx. 50% in order to reduce the power consumption of the Led\u2019s. If white, for instance, is used at full brightness we can expect there to be a 60 mA draw <strong><em>per<\/em><\/strong> LED. As there are 12 LED rings (one for each side) each with 12 RGB Led\u2019s, the total current draw would be a wopping 144 x 60 mA = 8.64 Amps which is way over the capability of the power system.<\/p>\n<p>However, only the top face is used for the continuous status of the timer limiting the amperage to a maximum of 60 mA x 12 = 720mA. Having just one colour further reduces this to 20 mA x 12 = 240mA. This is even further reduced by a lew brightness giving a measured average of around 40mA.<\/p>\n<p>Side Note : In reality, for a production device of this size its very unlikely that so many LED\u2019s would be used.<\/p>\n<h3><a name=\"_Toc106031800\"><\/a>Battery &amp; Fuel Gauge<\/h3>\n<p>The fuel gauge allows the device to monitor the remaining power and let the user know if it needs charging. A slow flashing LED can be used to indicate the need for a charge.<\/p>\n<h3><a name=\"_Toc106031801\"><\/a>3.3 v Regulator<\/h3>\n<p>The\u00a0 device regulates the incoming power from the Lipo battery to a constant 3.3v.<\/p>\n<p>The regulator used is the TPS6306x by Texas Instruments. Its is a Buck-Boost converter with a max current draw of up to 2A which is far more then the device will need to consume<\/p>\n<h3><a name=\"_Toc106031802\"><\/a>Battery<\/h3>\n<p>The battery is a LIPO 3.7V 2000mAh from MakerFocus.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_13 et_pb_row et_block_row\">\n<div class=\"et_pb_column_15 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_10 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h1><a name=\"_Toc106031803\"><\/a>Power Design &amp; considerations<\/h1>\n<p>The system can run off 3.3V for all peripherals except the Addressable LEDs. While the LED rings are designed for 5V operation they appear to work well enough on 3.3v, particularly the logic 1 &amp; 0 levels. However the power supply will need to be able to deliver a maximum of 500mA to the LED\u2019s directly to cater for the power consumption. A far lower power rating is achievable if only 2 rings at most are at full use and brightness.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_14 et_pb_row et_block_row\">\n<div class=\"et_pb_column_16 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_5 et_pb_image et_pb_module et_flex_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/04\/Component-wiring.png\" title=\"Component wiring\" class=\"wp-image-5141\" \/><\/span><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_15 et_pb_row et_block_row\">\n<div class=\"et_pb_column_17 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_11 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2>Software Description<\/h2>\n<p>Imported Software and Licenses<\/p>\n<p>The device uses three libraries from an external source<\/p>\n<ol>\n<li>DMA control for the Addressable LED\u2019s\n<ol>\n<li>GitHub - <a href=\"https:\/\/github.com\/hey-frnk\/STM32_HAL_NeoPixel\">hey-frnk\/STM32_HAL_NeoPixel: SK6812 RGBW NeoPixel using STM32 HAL on NUCLEO-F042K6 STM32F042K6 STM32F0 (github.com)<\/a><\/li>\n<li>The sk6812.c file was used and modifieds for this devices purpose<\/li>\n<li>There is no licence information. Credit to the author Frank from VDF collective<\/li>\n<\/ol>\n<\/li>\n<li>MPU6050 Accelerometer\n<ol>\n<li>The main need for this library was for the Kalman filter to obtain angles in degrees from the accelerometer readings.<\/li>\n<li>Github <a href=\"https:\/\/github.com\/leech001\/MPU6050\">leech001\/MPU6050: STM32 HAL library for GY-521 (MPU6050) with Kalman filter (github.com)<\/a><\/li>\n<li>Licence \u2013 GNU Public Licence<\/li>\n<\/ol>\n<\/li>\n<li>Command Line Interface by Elecia White\n<ol>\n<li>MIT Licence<\/li>\n<\/ol>\n<\/li>\n<\/ol>\n<p>\u00a0<\/p>\n<h3><a name=\"_Toc106031806\"><\/a>Original code<\/h3>\n<p>All code except the following have been developed by myself<\/p>\n<p><strong>Command Line Interface <\/strong>\u2013 Elecia White \u2013 have made some modifications and fixed an issue where a shorter command and a longer command with the same initial\u00a0 letters can be confused. See ConsoleCommandMatch where there is an additional check for the length of the commands to ensure no overlap happens.<\/p>\n<p>For instance if I have two commands LED and LEDOFF then the match command will select LEDOFF when LED was entered <strong>IF<\/strong> the LED command is first in the command list table. The code needs to check for the length of the command as well.<\/p>\n<p>I also changed the command line procees to use a circular buffer \u00a0- not necessary in the least except that it was an opportunity to add in a Circular Buffer.<\/p>\n<p><strong>Circular Buffer<\/strong> \u2013 This is a direct copy of the circular buffer conde contained in Elecia Whites book \u2018Making Embedded Systems\u2019 except for an additional function to detect and return a full string.<\/p>\n<p><strong>GY521 \u2013 MPU6050 Accelerometer <\/strong><\/p>\n<p>Used mainly for the calculation and Karmen algorithm.<\/p>\n<p><strong>WB2812 DMA driven PWM for addressable LED\u2019s<\/strong><\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_16 et_pb_row et_block_row\">\n<div class=\"et_pb_column_18 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_12 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2>Command Line Interface<\/h2>\n<p>The system uses a serial command line interface for both system check\/debugging as well as task and device management.<\/p>\n<p>Note:<\/p>\n<p>It would be better to use a WiFi or Bluetooth\u00a0 connection with an app to manage the tasks and log the data to a server. However, this project is to prove the embedded software and so the app\/web interface can be achieved at a later date.<\/p>\n<h3><a name=\"_Toc106031812\"><\/a>Commands<\/h3>\n<p>The face ID and the Task ID are the same and are linked when the task is assigned.<\/p>\n<table border=\"1\">\n<tbody>\n<tr>\n<td width=\"200\"><strong>Command<\/strong><\/td>\n<td width=\"200\"><strong>Parameters<\/strong><\/td>\n<td width=\"200\"><strong>Description<\/strong><\/td>\n<\/tr>\n<tr>\n<td width=\"200\">Help<\/td>\n<td width=\"200\">None<\/td>\n<td width=\"200\">Lists all the command line options<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">Reset!<\/td>\n<td width=\"200\">None<\/td>\n<td width=\"200\">Resets the device to factor settings. At this stage this is a set of predefined tasks allocated to different faces.<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">Reboot!<\/td>\n<td width=\"200\">None<\/td>\n<td width=\"200\">Software reboot<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">Ver<\/td>\n<td width=\"200\">None<\/td>\n<td width=\"200\">Displayes the firmware version running on the device<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">time?<\/td>\n<td width=\"200\">None<\/td>\n<td width=\"200\">Displays the current time from the RTC<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">date?<\/td>\n<td width=\"200\">None<\/td>\n<td width=\"200\">Displays the current date from the RTC<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">time<\/td>\n<td width=\"200\">hh:mm:ss<\/td>\n<td width=\"200\">Sets the time<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">date<\/td>\n<td width=\"200\">dd-mm-yy<\/td>\n<td width=\"200\">Sets the date<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">acc?<\/td>\n<td width=\"200\"><\/td>\n<td width=\"200\">reads the Accelerometer values<\/td>\n<\/tr>\n<tr>\n<td width=\"200\"><\/td>\n<td width=\"200\">r \u2013 readn \u2013 number of times to read<\/p>\n<p>\u00a0<\/p>\n<\/td>\n<td width=\"200\"><\/td>\n<\/tr>\n<tr>\n<td width=\"200\"><\/td>\n<td width=\"200\">g \u2013 get register valuen \u2013 register address to retrieve<\/td>\n<td width=\"200\">Gets the hex value of a register<\/td>\n<\/tr>\n<tr>\n<td width=\"200\"><\/td>\n<td width=\"200\">w \u2013 Write Registern \u2013 Register address<\/p>\n<p>v \u2013 Register value<\/p>\n<\/td>\n<td width=\"200\">Sets a value for a specific register<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">lipo?<\/td>\n<td width=\"200\">None<\/td>\n<td width=\"200\">Reads the current battery voltage<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">led<\/td>\n<td width=\"200\"><\/td>\n<td width=\"200\">Controls for the Addressable LED\u2019s<\/td>\n<\/tr>\n<tr>\n<td width=\"200\"><\/td>\n<td width=\"200\">f \u2013 Set face colourn \u2013 Face number<\/p>\n<p>c- colour (r|g|b)<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<p>\u00a0<\/p>\n<\/td>\n<td width=\"200\">Set a specific dodecahedron face colour<\/td>\n<\/tr>\n<tr>\n<td width=\"200\"><\/td>\n<td width=\"200\">o<\/td>\n<td width=\"200\">turn off all LED\u2019s<\/td>\n<\/tr>\n<tr>\n<td width=\"200\"><\/td>\n<td width=\"200\">d<\/td>\n<td width=\"200\">do led display around all faces<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">faceup?<\/td>\n<td width=\"200\">none<\/td>\n<td width=\"200\">Displays the face ID and X\/Y angle of the accelerometer that is currently pointing up\u00a0<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">save<\/td>\n<td width=\"200\">None<\/td>\n<td width=\"200\">saves the Dodeca task allocation to flash<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">dodeca?<\/td>\n<td width=\"200\">None<\/td>\n<td width=\"200\">Lists all the tasks on the system<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">dodeca<\/td>\n<td width=\"200\"><\/td>\n<td width=\"200\">Sets the task information for the face that is currently facing up<\/td>\n<\/tr>\n<tr>\n<td width=\"200\"><\/td>\n<td width=\"200\">n<\/td>\n<td width=\"200\">Sets the name of the task<\/td>\n<\/tr>\n<tr>\n<td width=\"200\"><\/td>\n<td width=\"200\">e<\/td>\n<td width=\"200\">Enables the task<\/td>\n<\/tr>\n<tr>\n<td width=\"200\"><\/td>\n<td width=\"200\">d<\/td>\n<td width=\"200\">disables the task<\/td>\n<\/tr>\n<tr>\n<td width=\"200\"><\/td>\n<td width=\"200\">a<\/td>\n<td width=\"200\">Sets the Max task time<\/td>\n<\/tr>\n<tr>\n<td width=\"200\"><\/td>\n<td width=\"200\">i<\/td>\n<td width=\"200\">Sets the Min task time<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">config<\/td>\n<td width=\"200\"><\/td>\n<td width=\"200\">Enters Config Mode. This puts the state machine into config mode. No other state can run unless you exit this mode<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">exit<\/td>\n<td width=\"200\"><\/td>\n<td width=\"200\">Exist the Config mode and starts the state machine again.<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">dump<\/td>\n<td width=\"200\">none<\/td>\n<td width=\"200\">dumps the currently timed tasks to the terminal in comma delimited form<\/td>\n<\/tr>\n<tr>\n<td width=\"200\">clear<\/td>\n<td width=\"200\">none<\/td>\n<td width=\"200\">clears the task timed data.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_17 et_pb_row et_block_row\">\n<div class=\"et_pb_column_19 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_13 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p>The base code for the CLI is drawn from Elecia White\u2019s example CLI code from Woko, however the following changed and features have been implemented<\/p>\n<ol>\n<li>Use interrupts instead of polling for UART<\/li>\n<li>Used a circular buffer - This was mainly to demonstrate the use of a circular buffer. The command line interface does not usually requite one.<\/li>\n<\/ol>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_18 et_pb_row et_block_row\">\n<div class=\"et_pb_column_20 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_14 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><a name=\"_Toc106031813\"><\/a>Task Time Management<\/h2>\n<p>\u00a0<\/p>\n<h3><a name=\"_Toc106031814\"><\/a>Task Assignment<\/h3>\n<p>Each face of the dodecahedron can be assigned a different task. This ranges from work tasks to entertainment tasks to meal and rest times.<\/p>\n<p>Using the CLI, the user can assign tasks with the following parameters<\/p>\n<ul>\n<li>Task Name<\/li>\n<li>Maximum task duration<\/li>\n<li>Minimum task duration<\/li>\n<li>Task Colour<\/li>\n<li>Enable or Disable the task<\/li>\n<\/ul>\n<p>A task , can be started by reorientating the dodecahedron so that the task face is facing up. This logs the start time.<\/p>\n<p>A task can be stopped by either placing the dodecahedron on the STOP FACE or any of the disabled tasks.<\/p>\n<h3><a name=\"_Toc106031815\"><\/a>Configuration<\/h3>\n<p>The device allows for 12 tasks to be set up. The task configuration is saved to Flash.<\/p>\n<p>A 2K area of flash has been reserved in the linker script at the end of the flash area<\/p>\n<p>MEMORY<\/p>\n<p>See <strong><u>Linker Script<\/u><\/strong> under Software modules<\/p>\n<p>The configuration uses the CRC peripheral in order to calculate the config checksum \u2013 This is used to determine of the saved config is valid or not. If not the default settings are applied and saved back to flash.<\/p>\n<p>\u00a0<\/p>\n<p>A pointer to the config area is defined in the Config controller code.<\/p>\n<p><strong>__attribute__<\/strong>((__section__(\".systemConfig\"))) <strong>const<\/strong> <strong>char<\/strong> systemConfigROPtr<\/p>\n<p>The pointer is then set to a structure containing the definitrion of the configuration.<\/p>\n<p>Once the tasks have been configured via the console a \u2018save\u2019 command must be used to commit the config to flash.<\/p>\n<p>\u00a0<\/p>\n<h3><a name=\"_Toc106031816\"><\/a>Data logging structure<\/h3>\n<p>Data logging of each task is a simple array of a task struct. As, at this stage, there is only one task data type, the array is simply an array of the task data.<\/p>\n<p>Each time a tasks is stopped, q task record data is created and added to the array.<\/p>\n<p>When the data is \u2018dummped\u2019 there is a simple process to loop though the array and format the into a usable format.<\/p>\n<p>The Device uses the time_t type and mktime from \u2018time.h\u2019 to create a timestamp for the start end end times.<\/p>\n<p>\u00a0<\/p>\n<h3><a name=\"_Toc106031817\"><\/a>Addressable LED\u2019s<\/h3>\n<p>\u00a0<\/p>\n<p>Design and Inspiration taken from <a href=\"https:\/\/www.thevfdcollective.com\/blog\/stm32-and-sk6812-rgbw-led\">https:\/\/www.thevfdcollective.com\/blog\/stm32-and-sk6812-rgbw-led<\/a><\/p>\n<p>The driver used has been designed to cater for a large number of RGB led\u2019s by using only two bytes within the DMA buffer to write duty cycles to the timers PWM channel. The driver uses the \u2018pulse half complete\u2019 and \u2018pulse complete\u2019 interrupts to move new data into the byte that has completed. This allows for a \u2018double buffer\u2019 type arrangement which allows for any number of LED\u2019s to be used without the need to create a large PWM buffer to hold the entire \u2018byte per bit\u2019 PWM structure.<\/p>\n<h2><a name=\"_Toc106031818\"><\/a>System start up<\/h2>\n<p>\u00a0<\/p>\n<p>The system start up initialises the HAL drivers and sets the device up.<\/p>\n<p>Date and Time \u2013 As the RTC clock , at this stage, does not have battery back up (to be added), if the device is switched off the RTC information is lost.<\/p>\n<p>Upon boot up the RTC date and time is checked and is not set the device is automatically placed into config mode with a message o say that the date and time need setting.<\/p>\n<p>Sequence of Start up<\/p>\n<ol>\n<li>Init HAL<\/li>\n<li>Set System Clock<\/li>\n<li>Init all configured peripherals<\/li>\n<li>Switch off all LED\u2019s<\/li>\n<li>Initialise the System config<\/li>\n<li>Read in config and reset\/save if the config is invalid<\/li>\n<li>Initialise the Dedeca tasks with the retrieved task config<\/li>\n<li>Initialise the Data Store<\/li>\n<li>Initialise the Console<\/li>\n<li>Initialise the Accelerometer<\/li>\n<li>Detect which face is currently facing up<\/li>\n<li>Validate the current date<\/li>\n<li>Start State machine based on the validity of the date and time.<\/li>\n<\/ol>\n<p>\u00a0<\/p>\n<p>The main loop simply calls :-<\/p>\n<ol>\n<li>ConsoleProcess \u2013 to process any messages from the terminal<\/li>\n<li>StateController \u2013 to run the state machine<\/li>\n<\/ol>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_19 et_pb_row et_block_row\">\n<div class=\"et_pb_column_21 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_15 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h1><a name=\"_Toc106031819\"><\/a>Software Modules<\/h1>\n<p>&nbsp;<\/p>\n<h2><a name=\"_Toc106031820\"><\/a>CBuffer \u2013 Circular Buffer<\/h2>\n<p>The Command Line interface uses a circular buffer to receive data from the UART. This codes esentually the same as the code in Making Embeded Systems Chapter 6 page 177.<\/p>\n<p>I added a function to search the buffer for a string allowing the polling to do a single called to determine if a string exists with the buffer.<\/p>\n<h2><a name=\"_Toc106031821\"><\/a>Cli \u2013 Command Line Interface<\/h2>\n<p>This is the Command Line Interface which was ported from Elecia Whites code off Wokwi (<a href=\"https:\/\/wokwi.com\/projects\/324879108372693587\">RPi Pico with Elecia's CLI - Wokwi Arduino and ESP32 Simulator<\/a>)<\/p>\n<p>A function to Retrieve a string from the command line was also implemented. This is used for the naming of Dodeca Tasks<\/p>\n<p>See \u2018Software Descriptions\u2019 for a full list of commands<\/p>\n<h2><a name=\"_Toc106031822\"><\/a>Colours<\/h2>\n<p>Small utility to define some basic RGB colours and three functions to retrieve a colour either by Hex code, ID or Name.<\/p>\n<h2><a name=\"_Toc106031823\"><\/a>DataStore<\/h2>\n<p>This is a simple data store to store an array of recorded tasks. Each record contains the Dodeca Id and timing details. The data store allows for 30 records to be stored.<\/p>\n<p>The \u2018dump\u2019 command reads out this array of records and formats it into a useful output.<\/p>\n<p>In future this would be extended to allow for more records which could be stored on Flash or external EE.<\/p>\n<p>&nbsp;<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_20 et_pb_row et_block_row\">\n<div class=\"et_pb_column_22 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_16 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><a name=\"_Toc106031824\"><\/a>Dodeca<\/h2>\n<p>The Dodeca module encapsulates each of the 12 sides of the dodecahedron, keeping the name, assigned colour etc.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_21 et_pb_row et_block_row\">\n<div class=\"et_pb_column_23 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_17 et_pb_text et_pb_bg_layout_light et_pb_module et_flex_module\"><div class=\"et_pb_text_inner\"><pre><strong><span style=\"color: #00ccff;\">typedef struct<\/span><\/strong><br \/>{<br \/>\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #ffcc00;\">uint8_t<\/span> id;<br \/>\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #ffcc00;\">uint8_t<\/span> enabled;<br \/>  \u00a0 \u00a0 \u00a0 <span style=\"color: #ffcc00;\">char<\/span> name[DODECA_NAME_MAX];<br \/>\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #ffcc00;\">uint32_t<\/span> colour;<br \/>\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #ffcc00;\">uint8_t<\/span> minTimeMins;<br \/>\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #ffcc00;\">uint8_t<\/span> maxTimeMins;<br \/>\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #ffcc00;\">time_t<\/span> startTime;<br \/>\u00a0 \u00a0 \u00a0 \u00a0 <span style=\"color: #ffcc00;\">eDodecaState_t<\/span> state;<br \/>} <span style=\"color: #00ffff;\">dodecaItem_t<\/span>;<\/pre>\n<\/div><\/div>\n\n<div class=\"et_pb_dmb_code_snippet_0 et_pb_dmb_code_snippet et_pb_module preset--module--divibooster-code-snippet--n42rcrxnlq\"><div class=\"et_pb_module_inner\"><pre class=\"vscode-dark-plus\"><code class=\"hljs c show_linenums\">typedef struct{\n&nbsp; &nbsp; &nbsp; &nbsp; uint8_t id;\n&nbsp; &nbsp; &nbsp; &nbsp; uint8_t enabled;\n  &nbsp; &nbsp; &nbsp; char name[DODECA_NAME_MAX];\n&nbsp; &nbsp; &nbsp; &nbsp; uint32_t colour;\n&nbsp; &nbsp; &nbsp; &nbsp; uint8_t minTimeMins;\n&nbsp; &nbsp; &nbsp; &nbsp; uint8_t maxTimeMins;\n&nbsp; &nbsp; &nbsp; &nbsp; time_t startTime;\n&nbsp; &nbsp; &nbsp; &nbsp; eDodecaState_t state;\n} dodecaItem_t;<\/code><\/pre ><\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_22 et_pb_row et_block_row\">\n<div class=\"et_pb_column_24 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_18 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><table border=\"1\">\n<tbody>\n<tr>\n<td style=\"width: 170.328px;\"><strong>Function<\/strong><\/td>\n<td style=\"width: 152.672px;\"><strong>Description<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 170.328px;\">dodecaInit<\/td>\n<td style=\"width: 152.672px;\">Initialises the Dodeca struct<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 170.328px;\">dodecaReset<\/td>\n<td style=\"width: 152.672px;\">Re-iInitialises the data set with a predefined set of data \u2013 used for factory reset.<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 170.328px;\">dodegaGet<\/td>\n<td style=\"width: 152.672px;\">Retrieves a dodeca record by Id<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 170.328px;\">dodecaGetByState<\/td>\n<td style=\"width: 152.672px;\">Retrieves the first Dodeca based on state (not used)<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 170.328px;\">dodecaStart<\/td>\n<td style=\"width: 152.672px;\">Sets the start time and turns on the LED\u2019s for the dodeca.<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 170.328px;\">dodeacEnd<\/td>\n<td style=\"width: 152.672px;\">Creates a recordDodea_t and sets the end time. RecordDodeca is then saves to the datastore.<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2><a name=\"_Toc106031825\"><\/a>GY521 \u2013 MPU6050 Accelerometer<\/h2>\n<p>Most of the code in this module is from a library found on github. The main aspect of this library was to use the Karmen filter in order to retrieve the angle if the dodecahedron in degrees. This allows for the software to determine the which face is up.<\/p>\n<p>See \u2018Orientation Module\u2019<\/p>\n<h2><a name=\"_Toc106031826\"><\/a>Helpers<\/h2>\n<p>Small module which supplies a few utilities. The main one being the \u2018byteToBin\u2019 function which returns a binary string representation of a supplied byte.<\/p>\n<h2><a name=\"_Toc106031827\"><\/a>LC709203F<\/h2>\n<p>This is the driver for the Lipo Fuel gauge. It is a simple set of functions that retrieve\u00a0 the cell voltage and temp for display in the command line \u2018Lipo?\u2019 function.<\/p>\n<p>Future development would be to implement a full battery level indicator using a discharge curve.<\/p>\n<h2><a name=\"_Toc106031828\"><\/a>Led Controller Module<\/h2>\n<p>This module has two functions.<\/p>\n<p>LerSetFaceColour \u2013 The function takes two colours , a face id and a mode.<\/p>\n<p>The mode allows for different colour patters to be implemented<\/p>\n<p><strong>LED_FACE_MODE_ERROR<\/strong> \u2013 Will display every alternate led in a defines ERROR colour<\/p>\n<p><strong>LED_FACE_MODE_NORMAL<\/strong> \u2013 Will display the first colour supplied in all LED\u2019s<\/p>\n<p><strong>LED_FACE_MODE_HALF<\/strong> \u2013 Will use both supplied colours and display alternate LED\u2019s in the supplied colours<\/p>\n<p>\u00a0<\/p>\n<p>The second function runs a rainbow colour sequence starting with face 0 to face 11.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_23 et_pb_row et_block_row\">\n<div class=\"et_pb_column_25 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_19 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><a name=\"_Toc106031829\"><\/a>Orientation Module<\/h2>\n<p>This module determines the correct orientation of the dodecahedron. Each face has a range for the X &amp; Y values allowing for a bit of drift and un-level surfaces.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_24 et_pb_row et_flex_row\">\n<div class=\"et_pb_column_26 et_pb_column et-last-child et_flex_column et_pb_css_mix_blend_mode_passthrough et_flex_column_24_24 et_flex_column_24_24_tablet et_flex_column_24_24_phone\">\n<div class=\"et_pb_dmb_code_snippet_1 et_pb_dmb_code_snippet et_pb_module preset--module--divibooster-code-snippet--default\"><div class=\"et_pb_module_inner\"><pre class=\"default\"><code class=\"hljs\">typedef struct\n{\nuint8_t faceId;\nint16_t xRTop;\nint16_t xRBottom;\nint16_t yRTop;\nint16_t yRBottom;\n} faceTable_t;\n\nfaceTable_t faceTable[12] = {\n\n{ 0, -12 , 8 , -11 , 9 },\n{ 1, -11 , 9 , 61 , 81 },\n{ 2, 58 , 78 , 30 , 50 },\n{ 3, 23 , 43 , -80 , -60 },\n{ 4, -45 , -25 , -80 , -60 },\n{ 5, -76 , -56 , 33 , 53 },\n{ 6, -62 , -42 , -163, -143 },\n{ 7, -40 , -20 , 120 , 140 },\n{ 8, 18 , 38 , 121 , 141 },\n{ 9, 39 , 59 , -162, -142 },\n{ 10, -12 , 8 , -133, -113 },\n{ 11, -13 , 7 , -188, -168 }\n\n};<\/code><\/pre ><\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_25 et_pb_row et_block_row\">\n<div class=\"et_pb_column_27 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_20 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p>The function \u2018detectFaceUp\u2019 retrieves the current Karman angles and searches the table and finds a face that fits within the XY ranges.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_26 et_pb_row et_block_row\">\n<div class=\"et_pb_column_28 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_21 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><a name=\"_Toc106031830\"><\/a>RTC Controller Module<\/h2>\n<p>This module has functions to get and set the date and time.<\/p>\n<p>It will also create and return a timestamp (time_t) based on the current date and time in the RTC.<\/p>\n<p>Future work \u2013 Add function to set up the Alarm functions.<\/p>\n<h2><a name=\"_Toc106031831\"><\/a>StareController\u00a0 Module\u2013 State Machine<\/h2>\n<p>The State machine manages the control of the device after initialisation. The RTC interrupt was not implemented though there is space in the state machine for it. This was to be used for alarms and task timeouts.<\/p>\n<p>The State machine also allows for a \u2018config mode\u2019 which stops normal operation of the state machine to allow for the user to use the command line interface without the debugging info appearing. It was also useful during testing to be able to stop the state machine, change something and then start the state machine again.<\/p>\n<table width=\"624\" border=\"1\" style=\"width: 624px;\">\n<tbody>\n<tr>\n<td width=\"147\"><strong>State<\/strong><\/td>\n<td width=\"476\"><strong>Description<\/strong><\/td>\n<\/tr>\n<tr>\n<td width=\"147\">STATE_CONFIG<\/td>\n<td width=\"476\">Loops within this state to allow for the CLI to be used without interference<\/td>\n<\/tr>\n<tr>\n<td width=\"147\">STATE_IDLE<\/td>\n<td width=\"476\">State machine operational task. This state , at this stage, is used for checking if the user has requested Config mode. Further development would use this to check Interrupt flags and change the direction of flow based on these flags.<\/td>\n<\/tr>\n<tr>\n<td width=\"147\">STATE_CHECK_OREN<\/td>\n<td width=\"476\">This state checks the orientation of the dodecahedron. If the face has changes then the \u2018CHANGE TASK state is run.<\/td>\n<\/tr>\n<tr>\n<td width=\"147\">STATE_CHANGE_TASK<\/td>\n<td width=\"476\">This task manages the changing of tasks. If a current task is valid then it is stopped and the new task, if it is valid, is saved. The old task is saved to the datastore.<\/td>\n<\/tr>\n<tr>\n<td width=\"147\">STATE_SLEEP<\/td>\n<td width=\"476\">The device is put to sleep. Timer 9 is used to wake the device up after a number of seconds.<\/td>\n<\/tr>\n<tr>\n<td width=\"147\">STATE_BATTERY_TEST<\/td>\n<td width=\"476\">Not implemented yet.<\/td>\n<\/tr>\n<tr>\n<td width=\"147\">STATE_ERROR<\/td>\n<td width=\"476\">Tests the reason for the error and acts appropriately.<\/td>\n<\/tr>\n<tr>\n<td width=\"147\">STATE_BEGIN<\/td>\n<td width=\"476\">\u00a0<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h2><a name=\"_Toc106031832\"><\/a>System Config Module<\/h2>\n<p>This module saves a configuration to the internal flash memory of the chip. A system Configuration structure contains a list of the 12 dodeca_t structs.<\/p>\n<p>The sysConfigSave will calculate a CRC using the chips CRC peripheral. And then save it data to flash.<\/p>\n<p>The sysConfigread will read in the full config and test the CRC against the data retrieved. If the CRC fails, then a \u2018SYS_CONFIG_BAD_DATA\u2019 is returned. This allows the start up process to reset the device to default settings.<\/p>\n<p>Future work would be to include more setting in the config such as alarms or other notifications.<\/p>\n<p>&nbsp;<\/p>\n<p>See Linker Script for more details of the flash aspect.<\/p>\n<p>&nbsp;<\/p>\n<h2><a name=\"_Toc106031833\"><\/a>Ws8212 Module \u2013 DMA NeoPixels<\/h2>\n<p>This module contolles the NeoPixe LED\u2019s using DMA.<\/p>\n<p>I chose this library due to the novel way it uses a circular DMA buffer and a small buffer split into just two colour data sections. With the LED\u2019s being PWM controlled to send the data, each bit of the 32 bit colour value needs to be represented by a full byte which is fed into the PWM to alter the duty cycle. If this method was not used, I would have needed a buffer wich as capable of containing the 32 bit (or 3 byes for the RGB range) PWM representation of all 144 led. This would have lead to a buffer of (3 * 8 * 144 = 3.4K)<\/p>\n<p>Where as, with the two wide colour buffer it only needs<\/p>\n<p><em>3 * 8 * 2 =\u00a0 48<\/em><\/p>\n<p>The process works by filling the first two parts of the buffer with a PWM pattern for the first and second colour value and stating the DMA process. When the process is half complete the call back event triggers, when half the data has been sent, the old data is replaced by the next colour sequence, Then when finished, the second part is filled and the process starts again until all the LED\u2019s have been updated.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_27 et_pb_row et_block_row\">\n<div class=\"et_pb_column_29 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_22 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h2><a name=\"_Toc106031834\"><\/a>Linker Script<\/h2>\n<p>The linker script was modified to reserve the last 2k of Flash for config.<\/p>\n<p>A new memory definition was added as 0x807E800<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_28 et_pb_row et_block_row\">\n<div class=\"et_pb_column_30 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_dmb_code_snippet_2 et_pb_dmb_code_snippet et_pb_module preset--module--divibooster-code-snippet--default\"><div class=\"et_pb_module_inner\"><pre class=\"default\"><code class=\"hljs show_linenums\">\/* Memories definition *\/MEMORY{\nRAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K\nFLASH (rx) : ORIGIN = 0x8000000, LENGTH = 510K\nCONFIG (r) : ORIGIN = 0x807E800 , LENGTH = 2k\n}\n<\/code><\/pre ><\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_29 et_pb_row et_block_row\">\n<div class=\"et_pb_column_31 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_23 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p>In the Section, a new item was added called systemConfig. A \u2018NOLOAD\u2019 attribute was added. This ensures that when the device is flashed with a new image, the config section is protected and not over written.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_30 et_pb_row et_block_row\">\n<div class=\"et_pb_column_32 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_dmb_code_snippet_3 et_pb_dmb_code_snippet et_pb_module preset--module--divibooster-code-snippet--default\"><div class=\"et_pb_module_inner\"><pre class=\"default\"><code class=\"hljs\">.systemConfig (NOLOAD) :{. = ALIGN(4);\nKEEP(*(.systemConfig))\n. = ALIGN(4);\n} &gt; CONFIG\n\n\n\n<\/code><\/pre ><\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_31 et_pb_row et_block_row\">\n<div class=\"et_pb_column_33 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_24 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p>In the System Config Module, a pointer to the config section is created and overlayed on the config structure for easy access to the data.<\/p>\n<\/div><\/div>\n\n<div class=\"et_pb_dmb_code_snippet_4 et_pb_dmb_code_snippet et_pb_module preset--module--divibooster-code-snippet--default\"><div class=\"et_pb_module_inner\"><pre class=\"default\"><code class=\"hljs\">__attribute__((__section__(&quot;.systemConfig&quot;))) const char systemConfigROPtr;\n<\/code><\/pre ><\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_32 et_pb_row et_block_row\">\n<div class=\"et_pb_column_34 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_25 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><h1>Mechanical Design<\/h1>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_33 et_pb_row et_block_row\">\n<div class=\"et_pb_column_35 et_pb_column et_pb_column_4_4 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_text_26 et_pb_text et_pb_bg_layout_light et_pb_module et_block_module\"><div class=\"et_pb_text_inner\"><p>The physical device is made from \u00a0ply and 3D printed parts using Fusion 360 for the CAD drawing and modelling.<\/p>\n<h2><a name=\"_Toc106031836\"><\/a>Dodecahedron<\/h2>\n<p>The dodecahedron is made from 3mm ply, laser cut and designed to fit the internal components of the device. Each side of the dodecahedron contains a Neo Pixel ring of 12 LED\u2019s. The top and bottom sides have screw holes in order to bolt the component tower in place.<\/p>\n<p>The bottom \u00a0side exposes the USB connection of the dev. board which is used for charging.<\/p>\n<\/div><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_34 et_pb_row et_block_row\">\n<div class=\"et_pb_column_36 et_pb_column et_pb_column_1_2 et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_6 et_pb_image et_pb_module et_block_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/04\/Dodecahedron-face.png\" title=\"Dodecahedron face\" class=\"wp-image-5185\" \/><\/span><\/div>\n<\/div>\n\n<div class=\"et_pb_column_37 et_pb_column et_pb_column_1_2 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_7 et_pb_image et_pb_module et_block_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/10\/IMG_0897-1.jpeg\" title=\"IMG_0897\" class=\"wp-image-9069\" \/><\/span><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_35 et_pb_row et_block_row\">\n<div class=\"et_pb_column_38 et_pb_column et_pb_column_1_3 et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_8 et_pb_image et_pb_module et_block_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/04\/Component-Tower.png\" title=\"Component Tower\" class=\"wp-image-5183\" \/><\/span><\/div>\n<\/div>\n\n<div class=\"et_pb_column_39 et_pb_column et_pb_column_1_3 et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_9 et_pb_image et_pb_module et_block_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/04\/render.png\" title=\"render\" class=\"wp-image-5177\" \/><\/span><\/div>\n<\/div>\n\n<div class=\"et_pb_column_40 et_pb_column et_pb_column_1_3 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_10 et_pb_image et_pb_module et_block_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/10\/IMG_0901.jpeg\" title=\"IMG_0901\" class=\"wp-image-8975\" \/><\/span><\/div>\n<\/div>\n<\/div>\n\n<div class=\"et_pb_row_36 et_pb_row et_block_row\">\n<div class=\"et_pb_column_41 et_pb_column et_pb_column_1_3 et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_11 et_pb_image et_pb_module et_block_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/04\/2B73DF70-9825-4564-82F8-CFB9D1ED33C5-scaled.jpeg\" title=\"2B73DF70-9825-4564-82F8-CFB9D1ED33C5\" class=\"wp-image-5171\" \/><\/span><\/div>\n<\/div>\n\n<div class=\"et_pb_column_42 et_pb_column et_pb_column_1_3 et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_12 et_pb_image et_pb_module et_block_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/04\/8D57D3BE-6FA8-49ED-901E-E5AC1ABA7AEB-scaled.jpeg\" title=\"8D57D3BE-6FA8-49ED-901E-E5AC1ABA7AEB\" class=\"wp-image-5173\" \/><\/span><\/div>\n<\/div>\n\n<div class=\"et_pb_column_43 et_pb_column et_pb_column_1_3 et-last-child et_block_column et_pb_css_mix_blend_mode_passthrough\">\n<div class=\"et_pb_image_13 et_pb_image et_pb_module et_block_module\"><span class=\"et_pb_image_wrap\"><img decoding=\"async\" src=\"https:\/\/athousandprojects.com\/staging\/wp-content\/uploads\/2024\/04\/dodecaPhoto.png\" title=\"dodecaPhoto\" class=\"wp-image-5115\" \/><\/span><\/div>\n<\/div>\n<\/div>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>A dodecahedron that tracks your day \u2014 flip the face for the task you&#8217;re on and an STM32 logs the time, lights the side, and saves it to flash. The capstone build from Elecia White&#8217;s Making Embedded Systems course, with DMA-driven NeoPixels, an accelerometer for orientation, and a CLI over xBee RF.<\/p>\n","protected":false},"author":3,"featured_media":9995,"comment_status":"open","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"project_category":[51],"project_tag":[58,57],"single-post-status":[],"class_list":["post-5033","project","type-project","status-publish","has-post-thumbnail","hentry","project_category-electronics","project_tag-laser-cut","project_tag-led"],"acf":[],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/project\/5033","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/project"}],"about":[{"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/types\/project"}],"author":[{"embeddable":true,"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/comments?post=5033"}],"version-history":[{"count":21,"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/project\/5033\/revisions"}],"predecessor-version":[{"id":10534,"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/project\/5033\/revisions\/10534"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/media\/9995"}],"wp:attachment":[{"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/media?parent=5033"}],"wp:term":[{"taxonomy":"project_category","embeddable":true,"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/project_category?post=5033"},{"taxonomy":"project_tag","embeddable":true,"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/project_tag?post=5033"},{"taxonomy":"single-post-status","embeddable":true,"href":"https:\/\/athousandprojects.com\/staging\/wp-json\/wp\/v2\/single-post-status?post=5033"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}