add final prototype documentation

This commit is contained in:
King Kévin 2017-05-21 13:43:56 +02:00
parent 6df6c4e461
commit 086609f6c9
3 changed files with 197 additions and 161 deletions

View File

@ -11,16 +11,17 @@ technology
Clapperboards are used to synchronize audio and video tracks by clapping two wooden pieces. Clapperboards are used to synchronize audio and video tracks by clapping two wooden pieces.
This is then visible on the video and the sharp sound is also present on the audio. This is then visible on the video and the sharp sound is also present on the audio.
Using the scene and take number written on the clapperboard and spoke at the beginning of the recording it is possible to know which sound track corresponds to which video track. Using the scene and take number written on the clapperboard and announced at the beginning of the recording it is possible to know which sound track corresponds to which video track.
This clapper board improves this system with some features: This clapper board improves this system with some features:
- use 7-segment displays to show scene and take number (instead of having to manually write and erase it on the board) - use 7-segment displays to show number, instead of having to manually write and erase it on the board
- show audio and video track numbers (number used in the file names or the recordings) - episode, scene, and take
- show current time - two audio and video track numbers (number used in the file names or the recordings)
- current date, time, and frame number
- automatically increment the take and recording numbers - automatically increment the take and recording numbers
The numbers on the board can be adjusted by hand using button switches. The numbers on the board can be adjusted by hand using buttons.
board board
===== =====
@ -32,25 +33,28 @@ peripherals
=========== ===========
- 1x 8-digit 7-segment display based on the MAX7219 to display the date - 1x 8-digit 7-segment display based on the MAX7219 to display the date
- 1x 8-digit 7-segment display based on the MAX7219 to display the time (hours, minutes, seconds, frame) - 1x 8-digit 7-segment display based on the MAX7219 to display the time (hours, minutes, seconds) and frame number
- 7x 4-digit 7-segment display based on the TM1637 to display recording information - 7x 4-digit 7-segment display based on the TM1637 to display recording information
- 1x to display the chapter/episode - 1x to display the episode (or chapter)
- 1x to display the scene - 1x to display the scene
- 1x to display the take - 1x to display the take
- 2x to display the video file number - 2x to display the video file number
- 2x to display the audio file number - 2x to display the audio file number
- 1x 16-channel multiplexer to communicate with the 7-segments individually - 1x 16-channel multiplexer to communicate with the 7-segments individually
- 8x2 button switches to adjust the recording numbers and seconds - 8x2 button switches to adjust the recording numbers and seconds
- 1 button switch to detect clap - 1x button switch to detect clap
- 1x tilt sensor to detect movement - 1x shake sensor to detect movement and switch on the clapper board
- 1x DS1307 RTC to keep track of the time - 1x DS1307 RTC to keep track of the time (using a tiny RTC module)
- 1x I2C EEPROM to save numbers (also present on the tiny RTC module)
- 1x power switching board (to switch off power completely)
- 1x battery + protection, charge, and 5V step up circuit
connections connections
=========== ===========
Connect the peripherals the following way (peripheral signal; peripheral signal; micro-controller pin; micro-controller signal; comment): Connect the peripherals the following way (peripheral signal; peripheral pin; micro-controller pin; micro-controller signal; comment):
- DS1307 RTC to get the date - DS1307 RTC to get the date and EEPROM to save the numbers
- VCC; 8; ; +5V; - VCC; 8; ; +5V;
- GND; 4; ; GND; - GND; 4; ; GND;
- SCL; 6; PB10; I2C2_SCL; - SCL; 6; PB10; I2C2_SCL;
@ -65,8 +69,8 @@ Connect the peripherals the following way (peripheral signal; peripheral signal;
- 7x TM1637 to show the recording numbers - 7x TM1637 to show the recording numbers
- VDD; 16; ; +5V; - VDD; 16; ; +5V;
- GND; 1; ; GND; - GND; 1; ; GND;
- DIO; 17; PB7; GPIO; - DIO; 17; PB7; GPIO; display with no clock signal will ignore data activity
- CLK; 18; 3-9; I0-I6; on analog multiplexed - CLK; 18; 3-9; I0-I6; on analog multiplexer
- 1x CD74HC4067 16-channel multiplexer - 1x CD74HC4067 16-channel multiplexer
- VCC; 24; ; +5V; - VCC; 24; ; +5V;
- GND; 12; ; GND; - GND; 12; ; GND;
@ -76,13 +80,31 @@ Connect the peripherals the following way (peripheral signal; peripheral signal;
- S1; 11; PB4; GPIO; to select output - S1; 11; PB4; GPIO; to select output
- S2; 14; PB5; GPIO; to select output - S2; 14; PB5; GPIO; to select output
- S3; 13; ; GND; - S3; 13; ; GND;
- I0; 9; 18; CLK; TM1637 for - I0; 9; 18; CLK; TM1637 for audio 2
- I1; 8; 18; CLK; TM1637 for - I1; 8; 18; CLK; TM1637 for video 2
- I2; 7; 18; CLK; TM1637 for - I2; 7; 18; CLK; TM1637 for audio 1
- I3; 6; 18; CLK; TM1637 for - I3; 6; 18; CLK; TM1637 for video 1
- I4; 5; 18; CLK; TM1637 for - I4; 5; 18; CLK; TM1637 for episode
- I5; 4; 18; CLK; TM1637 for - I5; 4; 18; CLK; TM1637 for scene
- I6; 3; 18; CLK; TM1637 for - I6; 3; 18; CLK; TM1637 for take
- 1x power board (custom), including SW-18015P shake switch between collector of PNP and emitter (with pull-down resistor and diode between shake switch and emitter)
- GND; ; GND; step up voltage regulator;
- IN; ; 5V; step up voltage regulator;
- OUT; ; +5V; all other peripherals
- base of PNP; SWITCH; PB8; to control power to all peripherals
- not-collector connected pin of shake switch; ACTIVITY; PB1; to detect power-up activity
- 1x clap switch
- pin 1; 1; ; GND;
- pin 2; 2; PB14; ; to detect clapping action (add pull-up resistor to improve detection)
- 16x buttons, in a 4x4 matrix
- 4x row 0 buttons; ; PA0; ; row 0
- 4x row 1 buttons; ; PA1; ; row 1
- 4x row 2 buttons; ; PA2; ; row 2
- 4x row 3 buttons; ; PA3; ; row 3
- 4x column 0 buttons; ; PA4; ; column 0, with a pull-down resistor
- 4x column 1 buttons; ; PA5; ; column 1, with a pull-down resistor
- 4x column 2 buttons; ; PA6; ; column 2, with a pull-down resistor
- 4x column 3 buttons; ; PA15; ; column 3, with a pull-down resistor
All pins are configured using `define`s in the corresponding source code. All pins are configured using `define`s in the corresponding source code.
@ -124,6 +146,7 @@ USB
--- ---
The firmware offers serial communication over USART1 and USB (using the CDC ACM device class). The firmware offers serial communication over USART1 and USB (using the CDC ACM device class).
Date and time can be set over serial.
You can also reset the board by setting the serial width to 5 bits over USB. You can also reset the board by setting the serial width to 5 bits over USB.
To reset the board run `make reset`. To reset the board run `make reset`.

View File

@ -20,7 +20,7 @@
#pragma once #pragma once
/** enable debugging functionalities */ /** enable debugging functionalities */
#define DEBUG true #define DEBUG false
/** get the length of an array */ /** get the length of an array */
#define LENGTH(x) (sizeof(x) / sizeof((x)[0])) #define LENGTH(x) (sizeof(x) / sizeof((x)[0]))

291
main.c
View File

@ -56,22 +56,27 @@ volatile bool keep_alive_flag = false; /**< flag to restart shutdown counter on
volatile bool clap_flag = false; /**< flag set on clap */ volatile bool clap_flag = false; /**< flag set on clap */
/** @} */ /** @} */
#define POWER_SWITCH_PORT B /**< port to switch power of all devices (including this micro-controller) */
#define POWER_SWITCH_PIN 8 /**< pin to switch power of all devices (including this micro-controller) */
#define POWER_BUTTON_PORT B /**< port to detect power switching activity by shaking (to keep alive) */
#define POWER_BUTTON_PIN 1 /**< pin to detect power switching activity by shaking (to keep alive) */
#define SQUARE_WAVE_PORT B /**< port connected to RTC DS1307 square wave output */ #define SQUARE_WAVE_PORT B /**< port connected to RTC DS1307 square wave output */
#define SQUARE_WAVE_PIN 0 /**< pin connected to RTC DS1307 square wave output */ #define SQUARE_WAVE_PIN 0 /**< pin connected to RTC DS1307 square wave output */
volatile uint8_t rtc_seconds = 0; /**< number of seconds passed incremented by the square wave */ volatile uint8_t rtc_seconds = 0; /**< number of seconds passed, incremented by the square wave */
#define STANDBY_TIMEOUT 30 /**< number of seconds after last shake before going down */ #define STANDBY_TIMEOUT 30 /**< number of seconds after last shake before going down */
volatile uint16_t standby_timer = 0; /**< number of seconds since last wake-up/activity */ volatile uint16_t standby_timer = 0; /**< number of seconds since last power-up activity (using shake sensor) */
#define FRAME_TIMER 2 /**< timer to count frame time */ #define FRAME_TIMER 2 /**< timer to count frame time */
#define FRAME_RATE 25 /**< frame rate */ #define FRAME_RATE 25 /**< frame rate in frames per second */
volatile uint8_t frame_count = 0; /**< number of frames passed */ volatile uint8_t frame_count = 0; /**< number of frames passed */
#define BUZZER_TIMER 1 /**< timer to generate scene and take count */ #define BUZZER_TIMER 1 /**< timer to generate scene and take count */
#define BUZZER_1_PORT A /**< use timer 1 channel 1 (and it's negative) to driver buzzer */ #define BUZZER_1_PORT A /**< use timer channel 1 (and it's negative) to driver buzzer */
#define BUZZER_1_PIN 7 /**< use timer 1 channel 1 (and it's negative) to driver buzzer */ #define BUZZER_1_PIN 7 /**< use timer channel 1 (and it's negative) to driver buzzer */
#define BUZZER_2_PORT A /**< use timer 1 channel 1 (and it's negative) to driver buzzer */ #define BUZZER_2_PORT A /**< use timer channel 1 (and it's negative) to driver buzzer */
#define BUZZER_2_PIN 8 /**< use timer 1 channel 1 (and it's negative) to driver buzzer */ #define BUZZER_2_PIN 8 /**< use timer channel 1 (and it's negative) to driver buzzer */
#define MUX_EN_PORT B /**< port to enable multiplexer */ #define MUX_EN_PORT B /**< port to enable multiplexer */
#define MUX_EN_PIN 9 /**< pin to enable multiplexer */ #define MUX_EN_PIN 9 /**< pin to enable multiplexer */
@ -102,11 +107,6 @@ struct number_t numbers[] = {
#define BUTTON_SECONDS_UP 9 /**< which of the 16 buttons is to increment the seconds */ #define BUTTON_SECONDS_UP 9 /**< which of the 16 buttons is to increment the seconds */
#define BUTTON_SECONDS_DOWN 13 /**< which of the 16 buttons is to decrement the seconds */ #define BUTTON_SECONDS_DOWN 13 /**< which of the 16 buttons is to decrement the seconds */
#define POWER_SWITCH_PORT B /**< port to switch power of all devices (including this micro-controller) */
#define POWER_SWITCH_PIN 8 /**< pin to switch power of all devices (including this micro-controller) */
#define POWER_BUTTON_PORT B /**< port to detect power switching activity (to keep alive) */
#define POWER_BUTTON_PIN 1 /**< pin to detect power switching activity (to keep alive) */
// buttons to adjust numbers and seconds (mutliplexed in a 4x4 matrix) // buttons to adjust numbers and seconds (mutliplexed in a 4x4 matrix)
#define BUTTONS_DRIVE_PORT A /**< port used to drive the buttons rows */ #define BUTTONS_DRIVE_PORT A /**< port used to drive the buttons rows */
#define BUTTONS_DRIVE_PIN0 0 /**< pin used to drive buttons row 0 */ #define BUTTONS_DRIVE_PIN0 0 /**< pin used to drive buttons row 0 */
@ -122,7 +122,7 @@ struct number_t numbers[] = {
#define CLAP_BUTTON_PORT B /**< port for button to detect clap action */ #define CLAP_BUTTON_PORT B /**< port for button to detect clap action */
#define CLAP_BUTTON_PIN 14 /**< port for button to detect clap action */ #define CLAP_BUTTON_PIN 14 /**< port for button to detect clap action */
/** Morse code variables, to buzz scene and take */ /** Morse code variables, to buzz/beep scene and take */
#define MORSE_DOT 1 /**< unit Morse code duration in frames */ #define MORSE_DOT 1 /**< unit Morse code duration in frames */
uint8_t morse[2*4*5*2] = {0}; /**< to encode 2 4-digit numbers (scene and take) into Morse code (5 sign+space) */ uint8_t morse[2*4*5*2] = {0}; /**< to encode 2 4-digit numbers (scene and take) into Morse code (5 sign+space) */
uint8_t morse_i = 0; /**< index in Morse array */ uint8_t morse_i = 0; /**< index in Morse array */
@ -237,8 +237,8 @@ error:
return; return;
} }
/** select output for TM1637 display using the multiplexer /** select clock output for TM1637 display using the analog multiplexer
* @param[in] output clock output * @param[in] output clock output channel
*/ */
static void mux_select(uint8_t output) static void mux_select(uint8_t output)
{ {
@ -292,21 +292,21 @@ static void mux_select(uint8_t output)
} }
} }
/** encode scene and take into Morse code (in morse) */ /** encode scene and take into Morse code (in morse variable) */
static void encode_morse(void) static void encode_morse(void)
{ {
// encode numbers (scene and take) in Morse code // numbers (scene and take) to encode in Morse code
uint16_t morse_numbers[] = {numbers[1].number, numbers[2].number}; uint16_t morse_numbers[] = {numbers[1].number, numbers[2].number};
printf("morsing scene: %u, take: %u\n", morse_numbers[0], morse_numbers[1]); printf("morsing scene: %u, take: %u\n", morse_numbers[0], morse_numbers[1]);
for (uint8_t morse_number=0; morse_number<LENGTH(morse_numbers); morse_number++) { for (uint8_t morse_number=0; morse_number<LENGTH(morse_numbers); morse_number++) {
bool not_zero = false; // has the first non-zero digit been found bool not_zero = false; // has the first non-zero digit been found
if (0xffff==morse_numbers[morse_number]) { // number disabled, don't beep if (0xffff==morse_numbers[morse_number]) { // number disabled, don't beep
for (uint8_t i=morse_number*4*2*5; i<(morse_number+1)*4*2*5; i++) { for (uint8_t i=morse_number*4*2*5; i<(morse_number+1)*4*2*5; i++) {
morse[i] = 0; morse[i] = 0; // no beeping
} }
} else { // encode number in Morse code } else { // encode number in Morse code
for (uint8_t digit=0; digit<4; digit++) { for (uint8_t digit=0; digit<4; digit++) { // encode each digit
uint16_t number = morse_numbers[morse_number]; uint16_t number = morse_numbers[morse_number]; // digit to encode
// get only the digit from the number // get only the digit from the number
for (uint8_t divide=digit; divide<3; divide++) { for (uint8_t divide=digit; divide<3; divide++) {
number /= 10; number /= 10;
@ -318,97 +318,97 @@ static void encode_morse(void)
} }
// encode digit in Morse code (1=short, 3=long) // encode digit in Morse code (1=short, 3=long)
switch (number) { switch (number) {
case 1: case 1: // Morse code for 1: short, long, long, long, long
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; // long
break; break;
case 2: case 2: // Morse code for 2: short, short, long, long, long
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; // long
break; break;
case 3: case 3: // Morse code for 3: short, short, short, long, long
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; // long
break; break;
case 4: case 4: // Morse code for 4: short, short, short, short, long
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; // long
break; break;
case 5: case 5: // Morse code for 5: short, short, short, short, short
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; // short
break; break;
case 6: case 6: // Morse code for 6: long, short, short, short, short
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; // short
break; break;
case 7: case 7: // Morse code for 7: long, long, short, short, short
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; // short
break; break;
case 8: case 8: // Morse code for 8: long, long, long, short, short
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; // short
break; break;
case 9: case 9: // Morse code for 9: long, long, long, long, short
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; // short
break; break;
case 0: case 0: // Morse code for 0: long, long, long, long, long
if (not_zero) { if (not_zero) { // encode zero if they are not leading
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; // long
} else { //don't encode the first digits if they are zero } else { // don't encode the first digits if they are zero
morse[(morse_number*4+digit)*2*5+0] = 0; morse[(morse_number*4+digit)*2*5+0] = 0; // no beeping
morse[(morse_number*4+digit)*2*5+2] = 0; morse[(morse_number*4+digit)*2*5+2] = 0; // no beeping
morse[(morse_number*4+digit)*2*5+4] = 0; morse[(morse_number*4+digit)*2*5+4] = 0; // no beeping
morse[(morse_number*4+digit)*2*5+6] = 0; morse[(morse_number*4+digit)*2*5+6] = 0; // no beeping
morse[(morse_number*4+digit)*2*5+8] = 0; morse[(morse_number*4+digit)*2*5+8] = 0; // no beeping
} }
break; break;
} }
// fill the spaces between the dots // fill the spaces between the dots
for (uint8_t space=0; space<5; space++) { for (uint8_t space=0; space<5; space++) {
if (0==morse[(morse_number*4+digit)*2*5+space*2]) { if (0==morse[(morse_number*4+digit)*2*5+space*2]) { // don't add space if there is no Morse code
morse[(morse_number*4+digit)*2*5+space*2+1] = 0; morse[(morse_number*4+digit)*2*5+space*2+1] = 0; // no space
} else { } else { // add space between Morse codes
morse[(morse_number*4+digit)*2*5+space*2+1] = 1*MORSE_DOT; morse[(morse_number*4+digit)*2*5+space*2+1] = 1*MORSE_DOT; // add space
} }
} }
} }
} }
} }
morse[4*2*5+1] = 3*MORSE_DOT; // add silence between the two numbers morse[4*2*5+1] = 3*MORSE_DOT; // use longer silence between the two numbers
morse_i = 0; // reset Morse index morse_i = 0; // reset Morse index
} }
@ -466,10 +466,10 @@ void main(void)
// setup external RTC // setup external RTC
printf("setup external RTC: "); printf("setup external RTC: ");
rtc_ds1307_setup(); // setup external RTC module rtc_ds1307_setup(); // setup external RTC module
// enable square wave output and configure input interrupt // enable square wave output and configure input interrupt to count seconds
rtc_ds1307_write_square_wave(1); // enable 1 Hz square wave output to sync on seconds rtc_ds1307_write_square_wave(1); // enable 1 Hz square wave output to sync on seconds
rcc_periph_clock_enable(RCC_GPIO(SQUARE_WAVE_PORT)); // enable clock for GPIO rcc_periph_clock_enable(RCC_GPIO(SQUARE_WAVE_PORT)); // enable clock for GPIO
gpio_set_mode(GPIO(SQUARE_WAVE_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(SQUARE_WAVE_PIN)); // set button pin to input gpio_set_mode(GPIO(SQUARE_WAVE_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(SQUARE_WAVE_PIN)); // set pin to input
rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
exti_select_source(EXTI(SQUARE_WAVE_PIN), GPIO(SQUARE_WAVE_PORT)); // mask external interrupt of this pin only for this port exti_select_source(EXTI(SQUARE_WAVE_PIN), GPIO(SQUARE_WAVE_PORT)); // mask external interrupt of this pin only for this port
exti_set_trigger(EXTI(SQUARE_WAVE_PIN), EXTI_TRIGGER_FALLING); // trigger on falling edge of square wave (this is also when the RTC register are updated) exti_set_trigger(EXTI(SQUARE_WAVE_PIN), EXTI_TRIGGER_FALLING); // trigger on falling edge of square wave (this is also when the RTC register are updated)
@ -477,12 +477,12 @@ void main(void)
nvic_enable_irq(NVIC_EXTI_IRQ(SQUARE_WAVE_PIN)); // enable interrupt nvic_enable_irq(NVIC_EXTI_IRQ(SQUARE_WAVE_PIN)); // enable interrupt
printf("OK\n"); printf("OK\n");
// verify is external RTC is running // verify if external RTC is running
if (rtc_ds1307_oscillator_disabled()) { if (rtc_ds1307_oscillator_disabled()) {
printf("/!\\ RTC oscillator is disabled: the battery may be empty\n"); printf("/!\\ RTC oscillator is disabled: the battery may be empty\n");
rtc_ds1307_oscillator_enable(); // enable oscillator again rtc_ds1307_oscillator_enable(); // enable oscillator again
} }
// display date // get date
uint8_t* rtc_ds1307_time = rtc_ds1307_read_time(); // get time/date from external RTC uint8_t* rtc_ds1307_time = rtc_ds1307_read_time(); // get time/date from external RTC
if (rtc_ds1307_time==NULL) { if (rtc_ds1307_time==NULL) {
printf("could not get time from DS1307\n"); printf("could not get time from DS1307\n");
@ -491,7 +491,7 @@ void main(void)
printf("current date: 20%02u-%02u-%02u %02u:%02u:%02u\n", rtc_ds1307_time[6], rtc_ds1307_time[5], rtc_ds1307_time[4], rtc_ds1307_time[2], rtc_ds1307_time[1], rtc_ds1307_time[0]); printf("current date: 20%02u-%02u-%02u %02u:%02u:%02u\n", rtc_ds1307_time[6], rtc_ds1307_time[5], rtc_ds1307_time[4], rtc_ds1307_time[2], rtc_ds1307_time[1], rtc_ds1307_time[0]);
} }
// setup analog multiplexer for TM1637 clock // setup analog multiplexer for TM1637 clock signal (mutliplex the clock signal we output between the 7 TM1637 displays)
printf("setup multiplexer: "); printf("setup multiplexer: ");
rcc_periph_clock_enable(RCC_GPIO(MUX_EN_PORT)); // enable clock for GPIO port domain rcc_periph_clock_enable(RCC_GPIO(MUX_EN_PORT)); // enable clock for GPIO port domain
gpio_set_mode(GPIO(MUX_EN_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(MUX_EN_PIN)); // to enable/disable the multiplexer gpio_set_mode(GPIO(MUX_EN_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(MUX_EN_PIN)); // to enable/disable the multiplexer
@ -517,9 +517,7 @@ void main(void)
led_max7219_setup(2); // setup MAX7219 led_max7219_setup(2); // setup MAX7219
led_max7219_intensity(15,8,0xff); // set brightness max and enable all digits led_max7219_intensity(15,8,0xff); // set brightness max and enable all digits
led_max7219_test(true,0xff); // test all MAX7219 displays led_max7219_test(true,0xff); // test all MAX7219 displays
for (uint32_t i=0; i<5000000; i++) { // wait a bit to have the user check the display for (volatile uint32_t i=0; i<10000000; i++); // wait a bit to have the user check the displays
__asm__("nop");
}
// switch displays back off // switch displays back off
for (uint8_t tm1637=0; tm1637<LENGTH(numbers); tm1637++) { for (uint8_t tm1637=0; tm1637<LENGTH(numbers); tm1637++) {
mux_select(tm1637); mux_select(tm1637);
@ -533,11 +531,12 @@ void main(void)
// get and display numbers on TM1637 // get and display numbers on TM1637
for (uint8_t number=0; number<LENGTH(numbers); number++) { for (uint8_t number=0; number<LENGTH(numbers); number++) {
uint8_t bytes[2] = {0}; uint8_t bytes[2] = {0}; // bytes for the numbers
if (!rtc_ds1307_read_rom(number*LENGTH(bytes), bytes, LENGTH(bytes))) { if (!rtc_ds1307_read_rom(number*LENGTH(bytes), bytes, LENGTH(bytes))) { // get number from EEPROM
printf("could not get number from EEPROM\n"); printf("could not get number from EEPROM\n");
} }
numbers[number].number = (bytes[0]<<8)+bytes[1]; numbers[number].number = (bytes[0]<<8)+bytes[1]; // save number
// display number
mux_select(numbers[number].display); mux_select(numbers[number].display);
printf("number %u: ", number); printf("number %u: ", number);
if (0xffff==numbers[number].number) { if (0xffff==numbers[number].number) {
@ -549,14 +548,14 @@ void main(void)
} }
} }
// display date and time on MAX7219 // display date and time on MAX7219 displays
led_max7219_number(20000000+rtc_ds1307_time[6]*10000+rtc_ds1307_time[5]*100+rtc_ds1307_time[4], 0x14, 0); // display date on 1st display led_max7219_number(20000000+rtc_ds1307_time[6]*10000+rtc_ds1307_time[5]*100+rtc_ds1307_time[4], 0x14, 0); // display date on 1st display
led_max7219_number(rtc_ds1307_time[2]*1000000+rtc_ds1307_time[1]*10000+rtc_ds1307_time[0]*100, 0x54, 1); // display time on 2nd display led_max7219_number(rtc_ds1307_time[2]*1000000+rtc_ds1307_time[1]*10000+rtc_ds1307_time[0]*100, 0x54, 1); // display time on 2nd display
led_max7219_on(0xff); // switch displays on led_max7219_on(0xff); // switch displays on
// setup frame timer // setup timer to count frames
printf("setup frame timer: "); printf("setup frame timer: ");
rcc_periph_clock_enable(RCC_TIM(FRAME_TIMER)); // enable clock for timer block rcc_periph_clock_enable(RCC_TIM(FRAME_TIMER)); // enable clock for timer domain
timer_reset(TIM(FRAME_TIMER)); // reset timer state timer_reset(TIM(FRAME_TIMER)); // reset timer state
timer_set_mode(TIM(FRAME_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up timer_set_mode(TIM(FRAME_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
timer_set_prescaler(TIM(FRAME_TIMER), (rcc_ahb_frequency/0xffff+1)-1); // set the prescaler to so count up to one second timer_set_prescaler(TIM(FRAME_TIMER), (rcc_ahb_frequency/0xffff+1)-1); // set the prescaler to so count up to one second
@ -575,12 +574,14 @@ void main(void)
// setup PWM for piezo-buzzer // setup PWM for piezo-buzzer
printf("setup piezo-buzzer PWM timer: "); printf("setup piezo-buzzer PWM timer: ");
rcc_periph_clock_enable(RCC_GPIO(BUZZER_1_PORT)); // enable clock for GPIO peripheral rcc_periph_clock_enable(RCC_GPIO(BUZZER_1_PORT)); // enable clock for GPIO port domain
rcc_periph_clock_enable(RCC_AFIO); // enable clock for alternate function (PWM) rcc_periph_clock_enable(RCC_AFIO); // enable clock for alternate function (PWM)
gpio_primary_remap(AFIO_MAPR_SWJ_MASK, AFIO_MAPR_TIM1_REMAP_PARTIAL_REMAP); // remap TIM1_CH1N to PA7 instead of PB13 gpio_primary_remap(AFIO_MAPR_SWJ_MASK, AFIO_MAPR_TIM1_REMAP_PARTIAL_REMAP); // remap TIM1_CH1N to PA7 instead of PB13
gpio_set_mode(GPIO(BUZZER_1_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO(BUZZER_1_PIN)); // set pin as output to have a PWM to driver piezo buzzer gpio_set_mode(GPIO(BUZZER_1_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO(BUZZER_1_PIN)); // set pin as output to have a PWM to driver piezo buzzer
gpio_clear(GPIO(BUZZER_1_PORT), GPIO(BUZZER_1_PIN)); // ensure it's not beeping
rcc_periph_clock_enable(RCC_GPIO(BUZZER_2_PORT)); // enable clock for GPIO peripheral rcc_periph_clock_enable(RCC_GPIO(BUZZER_2_PORT)); // enable clock for GPIO peripheral
gpio_set_mode(GPIO(BUZZER_2_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO(BUZZER_2_PIN)); // set pin as output to have a PWM to driver piezo buzzer gpio_set_mode(GPIO(BUZZER_2_PORT), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO(BUZZER_2_PIN)); // set pin as output to have a PWM to driver piezo buzzer
gpio_clear(GPIO(BUZZER_2_PORT), GPIO(BUZZER_2_PIN)); // ensure it's not beeping
rcc_periph_clock_enable(RCC_TIM(BUZZER_TIMER)); // enable clock for timer peripheral rcc_periph_clock_enable(RCC_TIM(BUZZER_TIMER)); // enable clock for timer peripheral
timer_reset(TIM(BUZZER_TIMER)); // reset timer state timer_reset(TIM(BUZZER_TIMER)); // reset timer state
timer_set_mode(TIM(BUZZER_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up timer_set_mode(TIM(BUZZER_TIMER), TIM_CR1_CKD_CK_INT, TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP); // set timer mode, use undivided timer clock, edge alignment (simple count), and count up
@ -598,12 +599,11 @@ void main(void)
// setup GPIO for reading buttons // setup GPIO for reading buttons
printf("setup display buttons: "); printf("setup display buttons: ");
rcc_periph_clock_enable(RCC_GPIO(BUTTONS_DRIVE_PORT)); // enable clock for GPIO port domain rcc_periph_clock_enable(RCC_GPIO(BUTTONS_DRIVE_PORT)); // enable clock for GPIO port domain
// no need to configure the driving line modes since this will be done when they need to be driven // no need to configure the driving line modes since this will be done when they need to be driven individually
rcc_periph_clock_enable(RCC_GPIO(BUTTONS_READ_PORT)); // enable clock for GPIO port domain rcc_periph_clock_enable(RCC_GPIO(BUTTONS_READ_PORT)); // enable clock for GPIO port domain
gpio_set_mode(GPIO(BUTTONS_READ_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO(BUTTONS_READ_PIN0)|GPIO(BUTTONS_READ_PIN1)|GPIO(BUTTONS_READ_PIN2)|GPIO(BUTTONS_READ_PIN3)); // set read lines as input gpio_set_mode(GPIO(BUTTONS_READ_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(BUTTONS_READ_PIN0)|GPIO(BUTTONS_READ_PIN1)|GPIO(BUTTONS_READ_PIN2)|GPIO(BUTTONS_READ_PIN3)); // set read lines as input (external pull down resistors are required)
gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, 0); // enable PA15 (JTDI per default) gpio_primary_remap(AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON, 0); // enable PA15 (JTDI per default)
gpio_clear(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN0)|GPIO(BUTTONS_READ_PIN1)|GPIO(BUTTONS_READ_PIN2)|GPIO(BUTTONS_READ_PIN3)); // pull read lines low since they will be high when driven and button is pressed uint16_t buttons = 0; // to save button state
uint16_t buttons = 0;
printf("OK\n"); printf("OK\n");
printf("setup clap button: "); printf("setup clap button: ");
@ -620,20 +620,19 @@ void main(void)
// main loop // main loop
printf("command input: ready\n"); printf("command input: ready\n");
bool action = false; // if an action has been performed don't go to sleep bool action = false; // if an action has been performed don't go to sleep
button_flag = false; // reset button flag
char c = '\0'; // to store received character char c = '\0'; // to store received character
bool char_flag = false; // a new character has been received bool char_flag = false; // a new character has been received
while (true) { // main loop while (true) { // main loop
iwdg_reset(); // kick the dog iwdg_reset(); // kick the dog
while (usart_received) { // data received over UART while (usart_received) { // data received over UART
action = true; // action has been performed action = true; // action has been performed
led_toggle(); // toggle LED led_toggle(); // toggle LED to show activity
c = usart_getchar(); // store receive character c = usart_getchar(); // store receive character
char_flag = true; // notify character has been received char_flag = true; // notify character has been received
} }
while (cdcacm_received) { // data received over USB while (cdcacm_received) { // data received over USB
action = true; // action has been performed action = true; // action has been performed
led_toggle(); // toggle LED led_toggle(); // toggle LED to show activity
c = cdcacm_getchar(); // store receive character c = cdcacm_getchar(); // store receive character
char_flag = true; // notify character has been received char_flag = true; // notify character has been received
} }
@ -647,7 +646,7 @@ void main(void)
command_i = 0; // prepare for next command command_i = 0; // prepare for next command
process_command(command); // process user command process_command(command); // process user command
} }
} else { // user command input } else { // save user command input
command[command_i] = c; // save command input command[command_i] = c; // save command input
if (command_i<LENGTH(command)-2) { // verify if there is place to save next character if (command_i<LENGTH(command)-2) { // verify if there is place to save next character
command_i++; // save next character command_i++; // save next character
@ -678,17 +677,17 @@ void main(void)
led_max7219_text(time, 1); // display frame time on 2nd display led_max7219_text(time, 1); // display frame time on 2nd display
// Morse the scene and take numbers over the buzzer // Morse the scene and take numbers over the buzzer
if (morse_delay>0) { if (morse_delay>0) { // not ready to Morse
morse_delay--; morse_delay--; // still wait before Morsing
} else if (0==morse_delay) { } else if (0==morse_delay) { // ready to Morse
while (morse_i<LENGTH(morse)) { while (morse_i<LENGTH(morse)) { // until every code has been Morsed
if (morse[morse_i]) { // skip empty codes if (morse[morse_i]) { // skip empty codes
if (morse_i%2) { // switch buzzer on for odd code if (morse_i%2) { // switch buzzer on for odd code
timer_disable_counter(TIM(BUZZER_TIMER)); // stop buzzing timer_disable_counter(TIM(BUZZER_TIMER)); // stop buzzing
} else { } else {
timer_enable_counter(TIM(BUZZER_TIMER)); // start buzzing timer_enable_counter(TIM(BUZZER_TIMER)); // start buzzing
} }
morse[morse_i]--; // decrement beeping morse[morse_i]--; // decrement remaining buzzing time
break; // buzz for one frame break; // buzz for one frame
} else { } else {
morse_i++; // got to next code morse_i++; // got to next code
@ -696,35 +695,45 @@ void main(void)
} }
if (morse_i>=LENGTH(morse)) { // all codes done if (morse_i>=LENGTH(morse)) { // all codes done
morse_delay = -2; // Morse completed morse_delay = -2; // Morse completed
gpio_clear(GPIO(BUZZER_1_PORT), GPIO(BUZZER_1_PIN)); // ensure it's not beeping
gpio_clear(GPIO(BUZZER_2_PORT), GPIO(BUZZER_2_PIN)); // ensure it's not beeping
} }
} }
// read button inputs (drive and read each row since they are multiplexed) // read button inputs (drive and read each row since they are multiplexed)
uint16_t buttons_new = 0; uint16_t buttons_new = 0; // to save new button states
// drive row 0
gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(BUTTONS_DRIVE_PIN0)); gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(BUTTONS_DRIVE_PIN0));
gpio_set(GPIO(BUTTONS_DRIVE_PORT), GPIO(BUTTONS_DRIVE_PIN0)); gpio_set(GPIO(BUTTONS_DRIVE_PORT), GPIO(BUTTONS_DRIVE_PIN0));
gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(BUTTONS_DRIVE_PIN1)|GPIO(BUTTONS_DRIVE_PIN2)|GPIO(BUTTONS_DRIVE_PIN3)); gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(BUTTONS_DRIVE_PIN1)|GPIO(BUTTONS_DRIVE_PIN2)|GPIO(BUTTONS_DRIVE_PIN3));
// read all columns for this row
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN0)) ? 1 : 0)<<0); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN0)) ? 1 : 0)<<0);
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN1)) ? 1 : 0)<<1); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN1)) ? 1 : 0)<<1);
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN2)) ? 1 : 0)<<2); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN2)) ? 1 : 0)<<2);
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN3)) ? 1 : 0)<<3); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN3)) ? 1 : 0)<<3);
// drive row 1
gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(BUTTONS_DRIVE_PIN1)); gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(BUTTONS_DRIVE_PIN1));
gpio_set(GPIO(BUTTONS_DRIVE_PORT), GPIO(BUTTONS_DRIVE_PIN1)); gpio_set(GPIO(BUTTONS_DRIVE_PORT), GPIO(BUTTONS_DRIVE_PIN1));
gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(BUTTONS_DRIVE_PIN0)|GPIO(BUTTONS_DRIVE_PIN2)|GPIO(BUTTONS_DRIVE_PIN3)); gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(BUTTONS_DRIVE_PIN0)|GPIO(BUTTONS_DRIVE_PIN2)|GPIO(BUTTONS_DRIVE_PIN3));
// read all columns for this row
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN0)) ? 1 : 0)<<4); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN0)) ? 1 : 0)<<4);
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN1)) ? 1 : 0)<<5); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN1)) ? 1 : 0)<<5);
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN2)) ? 1 : 0)<<6); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN2)) ? 1 : 0)<<6);
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN3)) ? 1 : 0)<<7); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN3)) ? 1 : 0)<<7);
// drive row 2
gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(BUTTONS_DRIVE_PIN2)); gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(BUTTONS_DRIVE_PIN2));
gpio_set(GPIO(BUTTONS_DRIVE_PORT), GPIO(BUTTONS_DRIVE_PIN2)); gpio_set(GPIO(BUTTONS_DRIVE_PORT), GPIO(BUTTONS_DRIVE_PIN2));
gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(BUTTONS_DRIVE_PIN0)|GPIO(BUTTONS_DRIVE_PIN1)|GPIO(BUTTONS_DRIVE_PIN3)); gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(BUTTONS_DRIVE_PIN0)|GPIO(BUTTONS_DRIVE_PIN1)|GPIO(BUTTONS_DRIVE_PIN3));
// read all columns for this row
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN0)) ? 1 : 0)<<8); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN0)) ? 1 : 0)<<8);
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN1)) ? 1 : 0)<<9); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN1)) ? 1 : 0)<<9);
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN2)) ? 1 : 0)<<10); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN2)) ? 1 : 0)<<10);
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN3)) ? 1 : 0)<<11); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN3)) ? 1 : 0)<<11);
// drive row 3
gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(BUTTONS_DRIVE_PIN3)); gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, GPIO(BUTTONS_DRIVE_PIN3));
gpio_set(GPIO(BUTTONS_DRIVE_PORT), GPIO(BUTTONS_DRIVE_PIN3)); gpio_set(GPIO(BUTTONS_DRIVE_PORT), GPIO(BUTTONS_DRIVE_PIN3));
gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(BUTTONS_DRIVE_PIN0)|GPIO(BUTTONS_DRIVE_PIN1)|GPIO(BUTTONS_DRIVE_PIN2)); gpio_set_mode(GPIO(BUTTONS_DRIVE_PORT), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO(BUTTONS_DRIVE_PIN0)|GPIO(BUTTONS_DRIVE_PIN1)|GPIO(BUTTONS_DRIVE_PIN2));
// read all columns for this row
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN0)) ? 1 : 0)<<12); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN0)) ? 1 : 0)<<12);
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN1)) ? 1 : 0)<<13); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN1)) ? 1 : 0)<<13);
buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN2)) ? 1 : 0)<<14); buttons_new |= ((gpio_get(GPIO(BUTTONS_READ_PORT), GPIO(BUTTONS_READ_PIN2)) ? 1 : 0)<<14);
@ -733,17 +742,19 @@ void main(void)
buttons = buttons_new; // save new state buttons = buttons_new; // save new state
if (buttons_diff) { // only do something if there is a change if (buttons_diff) { // only do something if there is a change
//printf("button pressed: %016b\n", buttons); //printf("button pressed: %016b\n", buttons);
for (uint8_t number=0; number<LENGTH(numbers); number++) { for (uint8_t number=0; number<LENGTH(numbers); number++) { // check buttons for every number
if (buttons_diff&(1<<numbers[number].up) || buttons_diff&(1<<numbers[number].down)) { // buttons for number if (buttons_diff&(1<<numbers[number].up) || buttons_diff&(1<<numbers[number].down)) { // a button for the number has been pressed
if (buttons&(1<<numbers[number].up) && buttons&(1<<numbers[number].down)) { // both buttons are pressed if (buttons&(1<<numbers[number].up) && buttons&(1<<numbers[number].down)) { // both buttons are pressed
numbers[number].number = 0xffff; // disable number numbers[number].number = 0xffff; // disable number
} else if (buttons&(1<<numbers[number].up) && buttons_diff&(1<<numbers[number].up)) { // only up button has been pressed } else if (buttons&(1<<numbers[number].up) && buttons_diff&(1<<numbers[number].up)) { // only up button has been pressed
// increment number
if (0xffff==numbers[number].number) { if (0xffff==numbers[number].number) {
numbers[number].number = 0; numbers[number].number = 0;
} else { } else {
numbers[number].number = (numbers[number].number+1)%10000; numbers[number].number = (numbers[number].number+1)%10000;
} }
} else if (buttons&(1<<numbers[number].down) && buttons_diff&(1<<numbers[number].down)) { // only down button has been pressed } else if (buttons&(1<<numbers[number].down) && buttons_diff&(1<<numbers[number].down)) { // only down button has been pressed
// decrement number
if (0xffff==numbers[number].number) { if (0xffff==numbers[number].number) {
numbers[number].number = 9999; numbers[number].number = 9999;
} else if (0==numbers[number].number) { } else if (0==numbers[number].number) {
@ -752,18 +763,18 @@ void main(void)
numbers[number].number -= 1; numbers[number].number -= 1;
} }
} }
} // display numbers on TM1637
// display numbers on TM1637 mux_select(numbers[number].display);
mux_select(numbers[number].display); if (0xffff==numbers[number].number) {
if (0xffff==numbers[number].number) { led_tm1637_off();
led_tm1637_off(); } else {
} else { led_tm1637_number(numbers[number].number);
led_tm1637_number(numbers[number].number); }
} // save number
// save number uint8_t bytes[2] = {numbers[number].number>>8, numbers[number].number};
uint8_t bytes[2] = {numbers[number].number>>8, numbers[number].number}; if (!rtc_ds1307_write_rom(number*LENGTH(bytes), bytes, LENGTH(bytes))) {
if (!rtc_ds1307_write_rom(number*LENGTH(bytes), bytes, LENGTH(bytes))) { printf("could not set number on EEPROM\n");
printf("could not set number on EEPROM\n"); }
} }
} }
if ((buttons_diff&(1<<BUTTON_SECONDS_UP) && buttons&(1<<BUTTON_SECONDS_UP)) || (buttons_diff&(1<<BUTTON_SECONDS_DOWN) && buttons&(1<<BUTTON_SECONDS_DOWN))) { // buttons for time pressed if ((buttons_diff&(1<<BUTTON_SECONDS_UP) && buttons&(1<<BUTTON_SECONDS_UP)) || (buttons_diff&(1<<BUTTON_SECONDS_DOWN) && buttons&(1<<BUTTON_SECONDS_DOWN))) { // buttons for time pressed
@ -774,6 +785,7 @@ void main(void)
} else { } else {
// adjust time // adjust time
if (buttons_diff&(1<<BUTTON_SECONDS_UP) && buttons&(1<<BUTTON_SECONDS_UP)) { // up pressed if (buttons_diff&(1<<BUTTON_SECONDS_UP) && buttons&(1<<BUTTON_SECONDS_UP)) { // up pressed
// increment time by one second
if (!(23==rtc_ds1307_time[2] && 59==rtc_ds1307_time[1] && 59==rtc_ds1307_time[0])) { // don't handle date changes since it's too complex if (!(23==rtc_ds1307_time[2] && 59==rtc_ds1307_time[1] && 59==rtc_ds1307_time[0])) { // don't handle date changes since it's too complex
rtc_ds1307_time[0] += 1; rtc_ds1307_time[0] += 1;
while (rtc_ds1307_time[0]>=60) { while (rtc_ds1307_time[0]>=60) {
@ -789,6 +801,7 @@ void main(void)
} }
} }
} else if (buttons_diff&(1<<BUTTON_SECONDS_DOWN) && buttons&(1<<BUTTON_SECONDS_DOWN)) { // down pressed } else if (buttons_diff&(1<<BUTTON_SECONDS_DOWN) && buttons&(1<<BUTTON_SECONDS_DOWN)) { // down pressed
// decrement time by one second
if (!(0==rtc_ds1307_time[2] && 0==rtc_ds1307_time[1] && 0==rtc_ds1307_time[0])) { // don't handle date changes since it's too complex if (!(0==rtc_ds1307_time[2] && 0==rtc_ds1307_time[1] && 0==rtc_ds1307_time[0])) { // don't handle date changes since it's too complex
if (rtc_ds1307_time[0]>0) { if (rtc_ds1307_time[0]>0) {
rtc_ds1307_time[0] -= 1; rtc_ds1307_time[0] -= 1;
@ -804,7 +817,7 @@ void main(void)
} }
} }
rtc_seconds = rtc_ds1307_time[0]; // save seconds since this is only updated every minute rtc_seconds = rtc_ds1307_time[0]; // save seconds since this is only updated every minute
if (!rtc_ds1307_write_time(rtc_ds1307_time[0], rtc_ds1307_time[1], rtc_ds1307_time[2], rtc_ds1307_time[3], rtc_ds1307_time[4], rtc_ds1307_time[5], rtc_ds1307_time[6])) { if (!rtc_ds1307_write_time(rtc_ds1307_time[0], rtc_ds1307_time[1], rtc_ds1307_time[2], rtc_ds1307_time[3], rtc_ds1307_time[4], rtc_ds1307_time[5], rtc_ds1307_time[6])) { // save adjusted time to DS1307
printf("could not set time on DS1307: resetting\n"); printf("could not set time on DS1307: resetting\n");
rtc_ds1307_setup(); // resetting peripheral rtc_ds1307_setup(); // resetting peripheral
} }
@ -820,7 +833,7 @@ void main(void)
if (standby_timer>=STANDBY_TIMEOUT) { // standby timeout complete if (standby_timer>=STANDBY_TIMEOUT) { // standby timeout complete
// go into standby mode // go into standby mode
printf("shutting down\n"); printf("shutting down\n");
// increment and save take if there has been a clap // increment and save take and video/audio numbers if there has been a clap
if (-2==morse_delay) { if (-2==morse_delay) {
morse_delay = -1; // prevent incrementing multiple times morse_delay = -1; // prevent incrementing multiple times
uint8_t bytes[LENGTH(numbers)*2] = {0}; // all numbers to write again in EEPROM uint8_t bytes[LENGTH(numbers)*2] = {0}; // all numbers to write again in EEPROM
@ -851,7 +864,7 @@ void main(void)
rtc_ds1307_time = rtc_ds1307_read_time(); // get time/date from external RTC rtc_ds1307_time = rtc_ds1307_read_time(); // get time/date from external RTC
if (rtc_ds1307_time==NULL) { if (rtc_ds1307_time==NULL) {
printf("could not get time from DS1307: resetting\n"); printf("could not get time from DS1307: resetting\n");
rtc_ds1307_setup(); // resetting periph rtc_ds1307_setup(); // resetting peripheral
} else { } else {
rtc_seconds = rtc_ds1307_time[0]; // get actual number of seconds rtc_seconds = rtc_ds1307_time[0]; // get actual number of seconds
if (0==rtc_ds1307_time[1] && 0==rtc_ds1307_time[2]) { // new day arrived if (0==rtc_ds1307_time[1] && 0==rtc_ds1307_time[2]) { // new day arrived