This firmware template is designed for development boards based around [STM32 F1 series micro-controller](http://www.st.com/web/en/catalog/mmc/FM141/SC1169/SS1031).
The dachtür is a device to restrict access to the dachboden.
project
=======
@ -6,51 +6,161 @@ project
summary
-------
*describe project purpose*
Previously a button allowed to open the building's entrance door and granted access to the dachboden.
Since the dachboden got popular, it is now flooded.
The idea behind the dachtür it to disable this button and replace it with a secret sequence of button presses during certain periods (e.g. when parties are taking place in the dachboden).
It must be installed in the door panel, as described under `connections`.
technology
----------
configure
---------
*described electronic details*
To program the days, times, and button sequence, connect to the dachtür.
It should appear as "dachtuer" Bluetooth (classic) device.
A PIN is required to connect to it.
Once connected, you can use a terminal (such as the "Bluetooth terminal" android application).
Interact with it by entering commands.
- from time to time, update the date (it does not take into account summer and winter time):
~~~
date YYYY-MM-DD HH:MM
~~~
- enter the days on which the access should be restricted (starting with Monday, here only Thursday is active):
~~~
days 0001000
~~~
- enter at which time the restriction should start:
~~~
start 20:00
~~~
- enter at which time the restriction should stop:
~~~
stop 06:00
~~~
- enter the secret button sequence to open the door (here press button 1 then 2):
~~~
password 12
~~~
board
=====
The current implementation uses a [core board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#core_board).
The underlying template also supports following board:
- [Maple Mini](http://leaflabs.com/docs/hardware/maple-mini.html), based on a STM32F103CBT6
- [System Board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#system_board), based on a STM32F103C8T6
- [blue pill](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#blue_pill), based on a STM32F103C8T6
- [black pill](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#black_pill), based on a STM32F103C8T6
- [core board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#core_board), based on a STM32F103C8T6
- [ST-LINK V2 mini](https://wiki.cuvoodoo.info/doku.php?id=jtag#mini_st-link_v2), a ST-LINK/V2 clone based on a STM32F101C8T6
- [USB-Blaster](https://wiki.cuvoodoo.info/doku.php?id=jtag#armjishu_usb-blaster), an Altera USB-Blaster clone based on a STM32F101C8T6
**Which board is used is defined in the Makefile**.
This is required to map the user LED and button provided on the board
The ST-LINK V2 mini clone has SWD test points on the board.
Because read protection is enabled, you will first need to remove the protection to be able to flash the firmware.
To remove the read protection (and erase flash), run `rake remove_protection` while a SWD adapter is connected.
The Altera USB-Blaster clone has a pin header for SWD and UART1 on the board.
SWD is disabled in the main firmware, and it has read protection.
To be able to flash using SWD (or the serial port), the BOOT0 pin must be set to 1 to boot the system memory install of the flash memory.
To set BOOT0 to 1, apply 3.3 V on R11, between the resistor and the reference designator, when powering the device.
The red LED should stay off while the green LED is on.
Now you can remove the read protection (and erase flash), run `rake remove_protection` while a SWD adapter is connected.
WARNING: If the internal backup battery gets empty and the device looses power, the configuration and date get lost (since there are stored in SRAM).
In this case, replace the battery and reconfigure the device.
connections
===========
Connect the peripherals the following way (STM32F10X signal; STM32F10X pin; peripheral pin; peripheral signal; comment):
On one side there are three XH-2.54 connectors.
- *list board to peripheral pin connections*
2-pin connector: 6-25 AC/DC power input
3-pin connector: opening button (the one already wired)
- 1 (left-most): common side of button (leave the bus bar connected)
- 2 (center): other side of the button (remove the cable)
- 3 (right-most): the cable which was connected to the button
4-pin connector: ring buttons (yet unused)
- 2 left-most pins: to button 1 of door panel
- 2 right-most pins: to button 2 of door panel
On the other side is a USB connector.
This is used to flash and configure the micro-controller.
peripherals
===========
The XH-2.54 2P connector is for the 15V AC power input.
A full bridge rectifier and smoothing capacitor make a DC power supply out of it.
A buck converter module steps it down to 5V.
Under 50 mA of power consumption it is very inefficient.
With no load it has a quiescent current of 37 mA.
The 5V rail provides power to the blue pill, Bluetooth module, and boost converter.
The MT3608-based boost converter steps the voltage up to 9V for the omrom G6E-134P relays.
It is more efficient to re-use the existing 5V than stepping down the 15V because the buck converters drawn a large current under no load.
The XH-2.54 3P is to be connected to door opening button (the installer will know what I mean).
Two omrom G6E-134P relays will take control over the button.
This allows the door button to be used.
At the specified time intervals, this is disconnected.
When the right code is entered, the second relay simulates the button press and opens the door.
The relays are controlled by the board using two 2N7000 n-channel MOSFETs.
The XH-2.54 4P is to be connected with the two buttons.
They are used to enter the secret sequence to open the door.
The [blue pill](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#blue_pill), based on a STM32F103C8T6 micro-controller, will handle the logic.
A CR2032 battery is connected through a diode to VBAT.
This keeps the real time clock (RTC) running when there is no power from the panel.
A 3.3V pin is also connected through a diode to VBAT.
This powered the RTC when the board is powered, saving the battery.
The HC-05 Bluetooth module allows to remotely connect to the UART port.
It has been configured (using `hc-05_porg.rb`) to appear as "dachtuer", and requires a PIN to pair.
It offers the Serial Port Profile (SPP) from Bluetooth classic (Bluetooth Low Energy makes little sense).
This allows to communicate with the board without having to remove the panel.
It can be used to configure the opening time slots, days, and button sequence.
It is also possible to update the firmware through it.
A WS2812B LED strip is also connected to the board.
The LEDs should be placed behind the button name shield.
An animation with be shown when pressing the button (only during opening hours).
wiring
======
HC-05 Bluetooth module:
- STATE: no connect
- TXD: PA10/USART1_RX
- RXD: PA9/USART1_TX
- GND: ground
- VCC: 5V
- EN: no connect
CR2032 coin cell battery:
- +: VBAT, though diode (VBAT should also be connected to 3.3V through diode)
- -: ground
LED (because the on-board LED screws the LSE):
- anode: 3.3V, though resistor (1K)
- cathode: PB11
omrom G6E-134P relay (bottom, for button):
- 1 +: 9V
- 6 -: 2N7000 drain
- 7 COM: door button bar
- 10 NC: no connect
- 12 NO: other relay NO
2N7000 p-channel MOSFET (for bottom relay):
- 1 source: ground
- 2 gate: PB6 (pulled low)
- 3 drain: relay -
omrom G6E-134P relay (top, for panel):
- 1 +: 9V
- 6 -: 2N7000 drain
- 7 COM: wire to panel
- 10 NC: door button (where the wire was)
- 12 NO: other relay NO
2N7000 p-channel MOSFET (for top relay):
- 1 source: ground
- 2 gate: PB7 (pulled low)
- 3 drain: relay -
WS2812B RGB LED strip:
- VCC: 5V
- DIN: PB15
- GND: ground
XH-4P:
- 1: ground (for button 1)
- 2: PB8 (for button 1)
- 3: ground (for button 2)
- 4: PB9 (for button 2)
All pins are configured using `define`s in the corresponding source code.
The prototype uses a SZOMK AK-N-01 enclosures salvaged from a J-Link clone.
code
====
@ -83,13 +193,33 @@ It is up to the application to advertise USB DFU support (i.e. as does the provi
The `bootlaoder` image will be flashed using SWD (Serial Wire Debug).
For that you need an SWD adapter.
The `Makefile` uses a Black Magic Probe (per default), or a ST-Link V2 along OpenOCD software.
The `Makefile` uses a ST-Link V2 along OpenOCD software.
To flash the `booltoader` using SWD run `rake flash_booloader`.
Once the `bootloader` is flashed it is possible to flash the `application` over USB using the DFU protocol by running `rake flash`.
To force the bootloader to start the DFU mode press the user button or short a pin, depending on the board.
It is also possible to flash the `application` image using SWD by running `rake flash_application`.
It is also possible to flash the application over Bluetooth as follows:
~~~
# start bluetooth
sudo systemctl restart bluetooth
# pair device (you only need to do it once, and you need the PIN)
printf("- lot number: %c%c%c%c%c%c%c\n",DESIG_UNIQUE_ID2>>24,DESIG_UNIQUE_ID2>>16,DESIG_UNIQUE_ID2>>8,DESIG_UNIQUE_ID2>>0,DESIG_UNIQUE_ID1>>24,DESIG_UNIQUE_ID1>>16,DESIG_UNIQUE_ID1>>8);
constuint16_tpidr_partno=((*(uint32_t*)0xE00FFFE4&0xf)<<8)+(*(uint32_t*)0xE00FFFE0&0xff);// PART_0, PIDR0 bits[7:0] Part number bits[7:0], PART_1, PIDR1 bits[3:0] Part number bits[11:8]
time_ttime_rtc=mktime(&time_tm);// get back seconds
time_rtc-=rtc_offset;// remove start offset
time_start=time_rtc*RTC_TICKS_SECOND+(rtc_get_counter_val()-time_start);// update uptime with current date
rtc_set_counter_val(time_rtc*RTC_TICKS_SECOND);// save date/time to internal RTC
printf("date and time saved: %d-%02d-%02d %02d:%02d:%02d\n",1900+time_tm.tm_year,time_tm.tm_mon,time_tm.tm_mday,time_tm.tm_hour,time_tm.tm_min,time_tm.tm_sec);
printf("date and time saved: %d-%02d-%02d %02d:%02d:%02d\n",1900+time_tm.tm_year,1+time_tm.tm_mon,time_tm.tm_mday,time_tm.tm_hour,time_tm.tm_min,time_tm.tm_sec);
// set watchdog to exit system memory after some time
iwdg_set_period_ms(25000);// set independent watchdog period (26214.4 ms if the max timeout)
iwdg_start();// start independent watchdog
iwdg_reset();// restart timer
// start system memory
constuint32_taddress=0x1FFFF000;// system memory address
SCB_VTOR=(volatileuint32_t)(address);// set vector table to application vector table (store at the beginning of the application)
__asm__volatile("MSR msp,%0"::"r"(*(uint32_t*)address));// set stack pointer to address provided in the beginning of the application (loaded into a register first)
(*(void(**)(void))((uint32_t)address+4))();// start system memory (by jumping to the reset function which address is stored as second entry of the vector table)
while(true);// this should not be reached
}
/** process user command
*@param[in]strusercommandstring(\0ended)
*/
@ -530,7 +638,7 @@ void main(void)
uart_setup();// setup USART (for printing)
#endif
usb_cdcacm_setup();// setup USB CDC ACM (for printing)
puts("\nwelcome to the CuVoodoo STM32F1 example application\n");// print welcome message
puts("\nwelcome to the dachboden door panel\n");// print welcome message
#if DEBUG
// show reset cause
@ -572,17 +680,88 @@ void main(void)
// setup RTC
puts("setup internal RTC: ");
#if defined(BLUE_PILL) || defined(STLINKV2) || defined(BLASTER) // for boards without a Low Speed External oscillator
// note: the blue pill LSE oscillator is affected when toggling the onboard LED, thus prefer the HSE
rtc_auto_awake(RCC_HSE,8000000/128/RTC_TICKS_SECOND-1);// use High Speed External oscillator (8 MHz / 128) as RTC clock (VBAT can't be used to keep the RTC running)
#else // for boards with an precise Low Speed External oscillator
// note: the blue pill LSE oscillator is affected when toggling the onboard LED -> DON'T USE THE ONBOARD LED since we want to use the LSE
rtc_auto_awake(RCC_LSE,32768/RTC_TICKS_SECOND-1);// ensure internal RTC is on, uses the 32.678 kHz LSE, and the prescale is set to our tick speed, else update backup registers accordingly (power off the micro-controller for the change to take effect)
#endif
rtc_interrupt_enable(RTC_SEC);// enable RTC interrupt on "seconds"
nvic_enable_irq(NVIC_RTC_IRQ);// allow the RTC to interrupt
time_start=rtc_get_counter_val();// get start time from internal RTC
puts("OK\n");
// setup relays
puts("setup relays: ");
rcc_periph_clock_enable(GPIO_RCC(RELAY_PANEL_PIN));// enable clock for GPIO domain
gpio_clear(GPIO_PORT(RELAY_PANEL_PIN),GPIO_PIN(RELAY_PANEL_PIN));// set low to leave per default
gpio_set_mode(GPIO_PORT(RELAY_PANEL_PIN),GPIO_MODE_OUTPUT_2_MHZ,GPIO_CNF_OUTPUT_PUSHPULL,GPIO_PIN(RELAY_PANEL_PIN));// set as output to control the transistor controlling the relay
rcc_periph_clock_enable(GPIO_RCC(RELAY_BUTTON_PIN));// enable clock for GPIO domain
gpio_clear(GPIO_PORT(RELAY_BUTTON_PIN),GPIO_PIN(RELAY_BUTTON_PIN));// set low to leave per default
gpio_set_mode(GPIO_PORT(RELAY_BUTTON_PIN),GPIO_MODE_OUTPUT_2_MHZ,GPIO_CNF_OUTPUT_PUSHPULL,GPIO_PIN(RELAY_BUTTON_PIN));// set as output to control the transistor controlling the relay
puts("OK\n");
// setup buttons
puts("setup buttons: ");
rcc_periph_clock_enable(RCC_AFIO);// enable alternate function clock for external interrupt
rcc_periph_clock_enable(GPIO_RCC(BUTTON1_PIN));// enable clock for button
gpio_set(GPIO_PORT(BUTTON1_PIN),GPIO_PIN(BUTTON1_PIN));// pull up to be able to detect button push (go low)
gpio_set_mode(GPIO_PORT(BUTTON1_PIN),GPIO_MODE_INPUT,GPIO_CNF_INPUT_PULL_UPDOWN,GPIO_PIN(BUTTON1_PIN));// set button pin to input
exti_select_source(GPIO_EXTI(BUTTON1_PIN),GPIO_PORT(BUTTON1_PIN));// mask external interrupt of this pin only for this port
exti_set_trigger(GPIO_EXTI(BUTTON1_PIN),EXTI_TRIGGER_FALLING);// trigger when button is pressed
uint8_tanimation_progress=0;// index of the current animation
led_ws2812b_setup();
for(uint8_tled=0;led<LED_WS2812B_LEDS;led++){
led_ws2812b_set_rgb(led,0x10,0x10,0x10);
}
puts("OK\n");
puts("setup animation timer: ");
// setup timer to wait for minimal time before next transmission (after previous transmission or reception)
rcc_periph_clock_enable(RCC_TIM(LED_ANIMATION_TIMER));// enable clock for timer block
rcc_periph_reset_pulse(RST_TIM(LED_ANIMATION_TIMER));// reset timer state
timer_set_mode(TIM(LED_ANIMATION_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(LED_ANIMATION_TIMER),1099-1);// set the prescaler so this 16 bits timer allows to wait for maximum 1s ( 1 / (72E6 / 1099 / (2**16)) = 1.0003s)
timer_set_period(TIM(LED_ANIMATION_TIMER),0xffff/16);// the timing is not defined in the specification. I tested until the communication was reliable (all requests get an response)
timer_clear_flag(TIM(LED_ANIMATION_TIMER),TIM_SR_UIF);// clear flag
timer_enable_irq(TIM(LED_ANIMATION_TIMER),TIM_DIER_UIE);// enable update interrupt for timer
nvic_enable_irq(NVIC_TIM_IRQ(LED_ANIMATION_TIMER));// catch interrupt in service routine
puts("OK\n");
// setup terminal
terminal_prefix="";// set default prefix
terminal_process=&process_command;// set central function to process commands
@ -591,6 +770,11 @@ void main(void)
// start main loop
boolaction=false;// if an action has been performed don't go to sleep
button_flag=false;// reset button flag
uint32_tlast_button_action=0;// the last time a button has been pressed
uint8_tbutton_pattern[LENGTH(opening_settings.button_pattern)];// to store the input button pattern
uint8_tbutton_input=0;// how many buttons have been pressed
boolrust_animated=false;// if the rust animation started
boolstrobe_animated=false;// if the strobe animation started
while(true){// infinite loop
iwdg_reset();// kick the dog
if(user_input_available){// user input is available
@ -599,19 +783,158 @@ void main(void)
charc=user_input_get();// store receive character
terminal_send(c);// send received character to terminal
}
if(button_flag){// user pressed button
if(button_flag||button_pressed){// user pressed button
action=true;// action has been performed
puts("button pressed\n");
led_toggle();// toggle LED
sleep_ms(100);// wait a bit to remove noise and double trigger
sleep_ms(200);// wait a bit to remove noise and double trigger