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.
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:
- use 7-segment displays to show scene and take 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)
- show current time
- use 7-segment displays to show number, instead of having to manually write and erase it on the board
- episode, scene, and take
- 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
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
=====
@ -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 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
- 1x to display the chapter/episode
- 1x to display the episode (or chapter)
- 1x to display the scene
- 1x to display the take
- 2x to display the video file number
- 2x to display the audio file number
- 1x 16-channel multiplexer to communicate with the 7-segments individually
- 8x2 button switches to adjust the recording numbers and seconds
- 1 button switch to detect clap
- 1x tilt sensor to detect movement
- 1x DS1307 RTC to keep track of the time
- 1x button switch to detect clap
- 1x shake sensor to detect movement and switch on the clapper board
- 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
===========
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;
- GND; 4; ; GND;
- 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
- VDD; 16; ; +5V;
- GND; 1; ; GND;
- DIO; 17; PB7; GPIO;
- CLK; 18; 3-9; I0-I6; on analog multiplexed
- DIO; 17; PB7; GPIO; display with no clock signal will ignore data activity
- CLK; 18; 3-9; I0-I6; on analog multiplexer
- 1x CD74HC4067 16-channel multiplexer
- VCC; 24; ; +5V;
- GND; 12; ; GND;
@ -76,13 +80,31 @@ Connect the peripherals the following way (peripheral signal; peripheral signal;
- S1; 11; PB4; GPIO; to select output
- S2; 14; PB5; GPIO; to select output
- S3; 13; ; GND;
- I0; 9; 18; CLK; TM1637 for
- I1; 8; 18; CLK; TM1637 for
- I2; 7; 18; CLK; TM1637 for
- I3; 6; 18; CLK; TM1637 for
- I4; 5; 18; CLK; TM1637 for
- I5; 4; 18; CLK; TM1637 for
- I6; 3; 18; CLK; TM1637 for
- I0; 9; 18; CLK; TM1637 for audio 2
- I1; 8; 18; CLK; TM1637 for video 2
- I2; 7; 18; CLK; TM1637 for audio 1
- I3; 6; 18; CLK; TM1637 for video 1
- I4; 5; 18; CLK; TM1637 for episode
- I5; 4; 18; CLK; TM1637 for scene
- 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.
@ -124,6 +146,7 @@ USB
---
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.
To reset the board run `make reset`.

View File

@ -20,7 +20,7 @@
#pragma once
/** enable debugging functionalities */
#define DEBUG true
#define DEBUG false
/** get the length of an array */
#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 */
/** @} */
#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_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 */
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_RATE 25 /**< frame rate */
#define FRAME_RATE 25 /**< frame rate in frames per second */
volatile uint8_t frame_count = 0; /**< number of frames passed */
#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_PIN 7 /**< use timer 1 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_PIN 8 /**< 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 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 channel 1 (and it's negative) to driver buzzer */
#define MUX_EN_PORT B /**< port 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_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)
#define BUTTONS_DRIVE_PORT A /**< port used to drive the buttons rows */
#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_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 */
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 */
@ -237,8 +237,8 @@ error:
return;
}
/** select output for TM1637 display using the multiplexer
* @param[in] output clock output
/** select clock output for TM1637 display using the analog multiplexer
* @param[in] output clock output channel
*/
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)
{
// 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};
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++) {
bool not_zero = false; // has the first non-zero digit been found
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++) {
morse[i] = 0;
morse[i] = 0; // no beeping
}
} else { // encode number in Morse code
for (uint8_t digit=0; digit<4; digit++) {
uint16_t number = morse_numbers[morse_number];
for (uint8_t digit=0; digit<4; digit++) { // encode each digit
uint16_t number = morse_numbers[morse_number]; // digit to encode
// get only the digit from the number
for (uint8_t divide=digit; divide<3; divide++) {
number /= 10;
@ -318,97 +318,97 @@ static void encode_morse(void)
}
// encode digit in Morse code (1=short, 3=long)
switch (number) {
case 1:
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT;
case 1: // Morse code for 1: short, long, long, long, long
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; // long
break;
case 2:
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT;
case 2: // Morse code for 2: short, short, long, long, long
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; // long
break;
case 3:
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT;
case 3: // Morse code for 3: short, short, short, long, long
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; // long
break;
case 4:
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT;
case 4: // Morse code for 4: short, short, short, short, long
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; // long
break;
case 5:
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT;
case 5: // Morse code for 5: short, short, short, short, short
morse[(morse_number*4+digit)*2*5+0] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; // short
break;
case 6:
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT;
case 6: // Morse code for 6: long, short, short, short, short
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+2] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; // short
break;
case 7:
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT;
case 7: // Morse code for 7: long, long, short, short, short
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+4] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; // short
break;
case 8:
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT;
case 8: // Morse code for 8: long, long, long, short, short
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+6] = 1*MORSE_DOT; // short
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; // short
break;
case 9:
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT;
case 9: // Morse code for 9: long, long, long, long, short
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+8] = 1*MORSE_DOT; // short
break;
case 0:
if (not_zero) {
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT;
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT;
} 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+2] = 0;
morse[(morse_number*4+digit)*2*5+4] = 0;
morse[(morse_number*4+digit)*2*5+6] = 0;
morse[(morse_number*4+digit)*2*5+8] = 0;
case 0: // Morse code for 0: long, long, long, long, long
if (not_zero) { // encode zero if they are not leading
morse[(morse_number*4+digit)*2*5+0] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+2] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+4] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+6] = 3*MORSE_DOT; // long
morse[(morse_number*4+digit)*2*5+8] = 3*MORSE_DOT; // long
} else { // don't encode the first digits if they are zero
morse[(morse_number*4+digit)*2*5+0] = 0; // no beeping
morse[(morse_number*4+digit)*2*5+2] = 0; // no beeping
morse[(morse_number*4+digit)*2*5+4] = 0; // no beeping
morse[(morse_number*4+digit)*2*5+6] = 0; // no beeping
morse[(morse_number*4+digit)*2*5+8] = 0; // no beeping
}
break;
}
// fill the spaces between the dots
for (uint8_t space=0; space<5; space++) {
if (0==morse[(morse_number*4+digit)*2*5+space*2]) {
morse[(morse_number*4+digit)*2*5+space*2+1] = 0;
} else {
morse[(morse_number*4+digit)*2*5+space*2+1] = 1*MORSE_DOT;
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; // no space
} else { // add space between Morse codes
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
}
@ -466,10 +466,10 @@ void main(void)
// setup external RTC
printf("setup external RTC: ");
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
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
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)
@ -477,12 +477,12 @@ void main(void)
nvic_enable_irq(NVIC_EXTI_IRQ(SQUARE_WAVE_PIN)); // enable interrupt
printf("OK\n");
// verify is external RTC is running
// verify if external RTC is running
if (rtc_ds1307_oscillator_disabled()) {
printf("/!\\ RTC oscillator is disabled: the battery may be empty\n");
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
if (rtc_ds1307_time==NULL) {
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]);
}
// 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: ");
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
@ -517,9 +517,7 @@ void main(void)
led_max7219_setup(2); // setup MAX7219
led_max7219_intensity(15,8,0xff); // set brightness max and enable all digits
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
__asm__("nop");
}
for (volatile uint32_t i=0; i<10000000; i++); // wait a bit to have the user check the displays
// switch displays back off
for (uint8_t tm1637=0; tm1637<LENGTH(numbers); tm1637++) {
mux_select(tm1637);
@ -533,11 +531,12 @@ void main(void)
// get and display numbers on TM1637
for (uint8_t number=0; number<LENGTH(numbers); number++) {
uint8_t bytes[2] = {0};
if (!rtc_ds1307_read_rom(number*LENGTH(bytes), bytes, LENGTH(bytes))) {
uint8_t bytes[2] = {0}; // bytes for the numbers
if (!rtc_ds1307_read_rom(number*LENGTH(bytes), bytes, LENGTH(bytes))) { // get number from EEPROM
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);
printf("number %u: ", 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(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
// setup frame timer
// setup timer to count frames
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_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
@ -575,12 +574,14 @@ void main(void)
// setup PWM for piezo-buzzer
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)
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_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
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
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
@ -598,12 +599,11 @@ void main(void)
// setup GPIO for reading buttons
printf("setup display buttons: ");
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
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_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;
uint16_t buttons = 0; // to save button state
printf("OK\n");
printf("setup clap button: ");
@ -620,20 +620,19 @@ void main(void)
// main loop
printf("command input: ready\n");
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
bool char_flag = false; // a new character has been received
while (true) { // main loop
iwdg_reset(); // kick the dog
while (usart_received) { // data received over UART
action = true; // action has been performed
led_toggle(); // toggle LED
led_toggle(); // toggle LED to show activity
c = usart_getchar(); // store receive character
char_flag = true; // notify character has been received
}
while (cdcacm_received) { // data received over USB
action = true; // action has been performed
led_toggle(); // toggle LED
led_toggle(); // toggle LED to show activity
c = cdcacm_getchar(); // store receive character
char_flag = true; // notify character has been received
}
@ -647,7 +646,7 @@ void main(void)
command_i = 0; // prepare for next command
process_command(command); // process user command
}
} else { // user command input
} else { // save user command input
command[command_i] = c; // save command input
if (command_i<LENGTH(command)-2) { // verify if there is place to 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
// Morse the scene and take numbers over the buzzer
if (morse_delay>0) {
morse_delay--;
} else if (0==morse_delay) {
while (morse_i<LENGTH(morse)) {
if (morse_delay>0) { // not ready to Morse
morse_delay--; // still wait before Morsing
} else if (0==morse_delay) { // ready to Morse
while (morse_i<LENGTH(morse)) { // until every code has been Morsed
if (morse[morse_i]) { // skip empty codes
if (morse_i%2) { // switch buzzer on for odd code
timer_disable_counter(TIM(BUZZER_TIMER)); // stop buzzing
} else {
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
} else {
morse_i++; // got to next code
@ -696,35 +695,45 @@ void main(void)
}
if (morse_i>=LENGTH(morse)) { // all codes done
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)
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(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));
// 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_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_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(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));
// 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_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_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(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));
// 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_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_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(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));
// 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_PIN1)) ? 1 : 0)<<13);
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
if (buttons_diff) { // only do something if there is a change
//printf("button pressed: %016b\n", buttons);
for (uint8_t number=0; number<LENGTH(numbers); number++) {
if (buttons_diff&(1<<numbers[number].up) || buttons_diff&(1<<numbers[number].down)) { // buttons for 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)) { // a button for the number has been pressed
if (buttons&(1<<numbers[number].up) && buttons&(1<<numbers[number].down)) { // both buttons are pressed
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
// increment number
if (0xffff==numbers[number].number) {
numbers[number].number = 0;
} else {
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
// decrement number
if (0xffff==numbers[number].number) {
numbers[number].number = 9999;
} else if (0==numbers[number].number) {
@ -752,18 +763,18 @@ void main(void)
numbers[number].number -= 1;
}
}
}
// display numbers on TM1637
mux_select(numbers[number].display);
if (0xffff==numbers[number].number) {
led_tm1637_off();
} else {
led_tm1637_number(numbers[number].number);
}
// save number
uint8_t bytes[2] = {numbers[number].number>>8, numbers[number].number};
if (!rtc_ds1307_write_rom(number*LENGTH(bytes), bytes, LENGTH(bytes))) {
printf("could not set number on EEPROM\n");
// display numbers on TM1637
mux_select(numbers[number].display);
if (0xffff==numbers[number].number) {
led_tm1637_off();
} else {
led_tm1637_number(numbers[number].number);
}
// save number
uint8_t bytes[2] = {numbers[number].number>>8, numbers[number].number};
if (!rtc_ds1307_write_rom(number*LENGTH(bytes), bytes, LENGTH(bytes))) {
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
@ -774,6 +785,7 @@ void main(void)
} else {
// adjust time
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
rtc_ds1307_time[0] += 1;
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
// 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 (rtc_ds1307_time[0]>0) {
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
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");
rtc_ds1307_setup(); // resetting peripheral
}
@ -820,7 +833,7 @@ void main(void)
if (standby_timer>=STANDBY_TIMEOUT) { // standby timeout complete
// go into standby mode
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) {
morse_delay = -1; // prevent incrementing multiple times
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
if (rtc_ds1307_time==NULL) {
printf("could not get time from DS1307: resetting\n");
rtc_ds1307_setup(); // resetting periph
rtc_ds1307_setup(); // resetting peripheral
} else {
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