Compare commits
34 Commits
master
...
clock_jock
Author | SHA1 | Date | |
---|---|---|---|
ac4731928b | |||
e7b5ddcdef | |||
2bda3be4a0 | |||
a5ba9f0aa5 | |||
3f8158e617 | |||
600264ce8c | |||
ee10d9aad3 | |||
ee615e65b1 | |||
0ae3087049 | |||
2ba33d58c6 | |||
0e1345c18d | |||
d88895ee0c | |||
4519bfa2d3 | |||
97c5faf5e5 | |||
f10b43e732 | |||
7078e37bc5 | |||
f858253f78 | |||
925c020c16 | |||
079cba9e1a | |||
e457f308e5 | |||
87db9a239e | |||
8096ae426b | |||
c9e2f9ea93 | |||
882ea71c4e | |||
363179e837 | |||
ecac618d67 | |||
666d1ed983 | |||
3bf0871f39 | |||
d74fd3aa09 | |||
cdc6eb6896 | |||
5810e72096 | |||
140f1126e6 | |||
781dd8f44d | |||
fdf800af4f |
111
README.md
111
README.md
@ -1,54 +1,97 @@
|
||||
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).
|
||||
|
||||
project
|
||||
=======
|
||||
|
||||
summary
|
||||
-------
|
||||
|
||||
*describe project purpose*
|
||||
this clock jockey monitors the tachometer of a motor turning a clock, and regulates its speed by switching the power to it.
|
||||
|
||||
technology
|
||||
----------
|
||||
|
||||
*described electronic details*
|
||||
the goal was to make a round clock quadrant turn.
|
||||
the quadrant is made out of wood, around 1 m heigh, and weights around 5 kg.
|
||||
it is mounted on a disco ball base.
|
||||
the bearing is strong enough to hold it and allow the clock to turn around its center.
|
||||
|
||||
originally the disco ball base included a motor, but it was too fragile to withhold the forces.
|
||||
two plastic gears in the gear box broke.
|
||||
this was the state of the clock when I joined the team.
|
||||
I decided to fix the turning clock.
|
||||
the small DC or stepper motor I tried were too weak to turn the clock.
|
||||
I decided to use a universal motor salvaged from a washing machine.
|
||||
|
||||
the pinout of the motor was undocumented, but not hard to figure out.
|
||||
two wires went to a small module at the end of the rotor shaft.
|
||||
this is the tachometer to measure the rotation speed.
|
||||
it is also easy to trace the two wires going to the brushes feeding the power to the rotor coils.
|
||||
next, measure the resistance of the remaining pin pairs.
|
||||
one will have 0 Ohms.
|
||||
this is the fuse to protect against over-heating.
|
||||
there will be two pairs of 0.6 Ohms, and one of 1.2 Ohms.
|
||||
these are the two coils for the stator, with a center tap.
|
||||
|
||||
wire the motor with 220V AC the following way:
|
||||
AC L - fuse - rotor - stator (2 coils, not center tap) - AC N
|
||||
to limit the speed I used a 4000 W capable SCR.
|
||||
the SCR was not enough to regulate the motor speed.
|
||||
setting the potentiometer to a fixed point would results in the motor to stop turning after some time, of to speed up to fast.
|
||||
the user would have to adjust the potentiometer using then knob periodically to have a somewhat constant speed.
|
||||
|
||||
to overcome this limitation I developed the clock jockey.
|
||||
this device will monitor the speed of the motor using the tachometer, and switch the power to the motor using a Solid State Relay (SSR), so to reach and stay at the predefined speed.
|
||||
|
||||
the motor tachometer provides an AC signal.
|
||||
basically it's a generating motor linked to the shaft of the actual motor.
|
||||
the AC frequency (and voltage) indicates the speed of the motor.
|
||||
the AC signal is rectified using a full bridge rectifier.
|
||||
the rectified signal is input to an PC817 optocoupler (with ~ 200 Ohm inline resistor).
|
||||
the full bridge rectifier protects to optocoupler, which has a reverse breakdown voltage of 6 V, lower than the seen -10 V peaks of the AC signal.
|
||||
it also allows to get two pulses per AC period, for a more accurate speed measurement.
|
||||
the optocoupler is directly connected to the clock jockey.
|
||||
an omron G3MB-202P (5V) is also connected to the clock jockey to switch to power going to the motor.
|
||||
the SCR is still in line to limit the maximum delivered power.
|
||||
|
||||
board
|
||||
=====
|
||||
|
||||
The current implementation uses a [core board](https://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#core_board).
|
||||
the device reuses an [ST-LINK/V2 clone](https://wiki.cuvoodoo.info/doku.php?id=jtag#mini_st-link_v2).
|
||||
this board uses a STM32F103C8T6 micro-controller.
|
||||
|
||||
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](ihttps://wiki.cuvoodoo.info/doku.php?id=stm32f1xx#blue_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.
|
||||
since the device is firmware protected (against read-out), you will first need to remove this protection using an SWD adapter and running `rake remove_protection`.
|
||||
you can then flash the bootloader using SWD and application using DFU a documented in the section below.
|
||||
|
||||
connections
|
||||
===========
|
||||
|
||||
Connect the peripherals the following way (STM32F10X signal; STM32F10X pin; peripheral pin; peripheral signal; comment):
|
||||
connect the peripherals the following way:
|
||||
|
||||
- *list board to preipheral pin connections*
|
||||
- PC817X emitter, SWIM pin (PB11, pulled up to 3V3 on board)
|
||||
- PC817X collector, GND
|
||||
- G3MB-202P SSR 3+, 5V (5V required by SSR, with embedded resistor)
|
||||
- G3MB-202P SSR 4-, SWDIO (SWCLK pin in not 5V tolerant)
|
||||
|
||||
All pins are configured using `define`s in the corresponding source code.
|
||||
all pins are configured using `define`s in the corresponding source code.
|
||||
|
||||
usage
|
||||
=====
|
||||
|
||||
the firmware will simply count the number of optocoupler falling edges (2 per revolution).
|
||||
it will periodically compare this count to the target value.
|
||||
if this is below, the SSR will be switched on.
|
||||
if it is above, the SSR will be switched off.
|
||||
|
||||
to set this target, connect the clock jokey to a computer.
|
||||
it will appear as a serial device (using the CDC ACM USB profile).
|
||||
use a serial terminal program and connect to it (the baud rate does not matter).
|
||||
enter `tacho xx`, with xx being the target tachometer count.
|
||||
to view the set and current tachometer values, enter `tacho`.
|
||||
|
||||
the target tachometer count is somewhat relative.
|
||||
it is proportional to the motor speed and tied to the periodic check (currently set to 0.1 s).
|
||||
|
||||
if the tacho count it at 0 for too many seconds after boot, the clock jockey will with off the power.
|
||||
this is a safety feature since the tachometer is either not reading the speed, or the motor is stuck.
|
||||
|
||||
code
|
||||
====
|
||||
@ -86,7 +129,7 @@ The `Makefile` uses a Black Magic Probe (per default), or a ST-Link V2 along Ope
|
||||
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.
|
||||
To force the bootloader to start the DFU mode, short the RST pin to the nearby ground pin.
|
||||
It is also possible to flash the `application` image using SWD by running `rake flash_application`.
|
||||
|
||||
debug
|
||||
@ -98,8 +141,4 @@ To start the debugging session run `rake debug`.
|
||||
USB
|
||||
---
|
||||
|
||||
The firmware offers serial communication over USART1 and USB (using the CDC ACM device class).
|
||||
|
||||
You can also reset the board by setting the serial width to 5 bits over USB.
|
||||
To reset the board run `rake reset`.
|
||||
This only works if provided USB CDC ACM is running correctly and the micro-controller isn't stuck.
|
||||
The firmware offers serial communication over USB (using the CDC ACM device class).
|
||||
|
2
Rakefile
2
Rakefile
@ -15,7 +15,7 @@ FIRMWARES = [BOOTLOADER, APPLICATION]
|
||||
|
||||
# which development board is used
|
||||
# supported are: SYSTEM_BOARD, MAPLE_MINI, BLUE_PILL, CORE_BOARD, STLINKV2, BLASTER, BUSVOODOO
|
||||
BOARD = ENV["BOARD"] || "CORE_BOARD"
|
||||
BOARD = ENV["BOARD"] || "STLINKV2"
|
||||
|
||||
# libopencm3 definitions
|
||||
LIBOPENCM3_DIR = "libopencm3"
|
||||
|
127
application.c
127
application.c
@ -15,7 +15,7 @@
|
||||
/** STM32F1 application example
|
||||
* @file application.c
|
||||
* @author King Kévin <kingkevin@cuvoodoo.info>
|
||||
* @date 2016-2019
|
||||
* @date 2016-2020
|
||||
*/
|
||||
|
||||
/* standard libraries */
|
||||
@ -37,6 +37,7 @@
|
||||
#include <libopencm3/stm32/dbgmcu.h> // debug utilities
|
||||
#include <libopencm3/stm32/desig.h> // design utilities
|
||||
#include <libopencm3/stm32/flash.h> // flash utilities
|
||||
#include <libopencm3/stm32/timer.h> // timer utilities
|
||||
|
||||
/* own libraries */
|
||||
#include "global.h" // board definitions
|
||||
@ -47,12 +48,16 @@
|
||||
#include "usb_cdcacm.h" // USB CDC ACM utilities
|
||||
#include "terminal.h" // handle the terminal interface
|
||||
#include "menu.h" // menu utilities
|
||||
#include "flash_internal.h" // menu utilities
|
||||
|
||||
#define WATCHDOG_PERIOD 10000 /**< watchdog period in ms */
|
||||
#define WATCHDOG_PERIOD 3000 /**< watchdog period in ms */
|
||||
/** set to 0 if the RTC is reset when the board is powered on, only indicates the uptime
|
||||
* set to 1 if VBAT can keep the RTC running when the board is unpowered, indicating the date and time
|
||||
*/
|
||||
#define RTC_DATE_TIME 1
|
||||
#define RTC_DATE_TIME 0
|
||||
|
||||
/** number of RTC ticks per second */
|
||||
#define RTC_TICKS 10
|
||||
|
||||
/** RTC time when device is started */
|
||||
static time_t time_start = 0;
|
||||
@ -63,6 +68,13 @@ static time_t time_start = 0;
|
||||
volatile bool rtc_internal_tick_flag = false; /**< flag set when internal RTC ticked */
|
||||
/** @} */
|
||||
|
||||
volatile uint32_t tacho_count = 0; /**< tachometer edge count */
|
||||
bool tacho_display = false; /**< if the current tachometer count should be displayed */
|
||||
#define TACHO_PIN PB11 /**< tachometer input on SWIM pin, pulled up to 3V3 by 680R */
|
||||
#define TACHO_TARGET_DEFAULT 20 /**< the default target tachometer count (slow for safety) */
|
||||
uint32_t tacho_target = TACHO_TARGET_DEFAULT; /**< the target tachometer count (switch SSR on when below, off when above) */
|
||||
#define SSR_PIN PB14 /**< pin to control the SSR (SWDIO, active low, open drain to 5V) */
|
||||
|
||||
size_t putc(char c)
|
||||
{
|
||||
size_t length = 0; // number of characters printed
|
||||
@ -117,6 +129,30 @@ static void command_reset(void* argument);
|
||||
*/
|
||||
static void command_bootloader(void* argument);
|
||||
|
||||
static void command_tacho(void* argument)
|
||||
{
|
||||
(void)argument; // we won't use the argument
|
||||
|
||||
if (argument) { // tachometer value has been provided
|
||||
uint32_t target = *(uint32_t*)argument; // get target tachometer value
|
||||
printf("setting target tachometer value to %u\n", target);
|
||||
tacho_target = target;
|
||||
// save to EEPROM
|
||||
const uint32_t eeprom_tacho[2] = {tacho_target, tacho_target ^ 0xffffffff};
|
||||
const int32_t rc = flash_internal_eeprom_write((uint8_t*)eeprom_tacho, sizeof(eeprom_tacho));
|
||||
if (rc != sizeof(eeprom_tacho)) {
|
||||
printf("could not save value to EEPROM: %d\n", rc);
|
||||
}
|
||||
} else {
|
||||
if (tacho_display) {
|
||||
tacho_display = false;
|
||||
} else {
|
||||
printf("target tachometer value set to %u\n", tacho_target);
|
||||
tacho_display = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** list of all supported commands */
|
||||
static const struct menu_command_t menu_commands[] = {
|
||||
{
|
||||
@ -169,6 +205,14 @@ static const struct menu_command_t menu_commands[] = {
|
||||
.argument_description = NULL,
|
||||
.command_handler = &command_bootloader,
|
||||
},
|
||||
{
|
||||
.shortcut = 't',
|
||||
.name = "tacho",
|
||||
.command_description = "set/show/hide tachometer target and current value",
|
||||
.argument = MENU_ARGUMENT_UNSIGNED,
|
||||
.argument_description = "[target]",
|
||||
.command_handler = &command_tacho,
|
||||
},
|
||||
};
|
||||
|
||||
static void command_help(void* argument)
|
||||
@ -330,7 +374,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 CuVoodoo dachboden clock turner\n"); // print welcome message
|
||||
|
||||
#if DEBUG
|
||||
// show reset cause
|
||||
@ -374,7 +418,7 @@ void main(void)
|
||||
printf("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 - 1); // use High Speed External oscillator (8 MHz / 128) as RTC clock (VBAT can't be used to keep the RTC running)
|
||||
rtc_auto_awake(RCC_HSE, 8000000 / 128 / RTC_TICKS - 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
|
||||
rtc_auto_awake(RCC_LSE, 32768 - 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
|
||||
@ -383,6 +427,40 @@ void main(void)
|
||||
time_start = rtc_get_counter_val(); // get start time from internal RTC
|
||||
printf("OK\n");
|
||||
|
||||
printf("setup SSR: ");
|
||||
rcc_periph_clock_enable(GPIO_RCC(SSR_PIN)); // enable clock for GPIO peripheral
|
||||
gpio_set(GPIO_PORT(SSR_PIN), GPIO_PIN(SSR_PIN)); // set high to switch off
|
||||
gpio_set_mode(GPIO_PORT(SSR_PIN), GPIO_MODE_OUTPUT_2_MHZ, GPIO_CNF_OUTPUT_OPENDRAIN, GPIO_PIN(SSR_PIN)); // set SSR - control pin to open drain. active low, connected to 5V on the + pin
|
||||
printf("OK\n");
|
||||
|
||||
// setup timer to measure motor tachometer
|
||||
printf("setup tachometer measurer: ");
|
||||
rcc_periph_clock_enable(GPIO_RCC(TACHO_PIN)); // enable clock for GPIO peripheral
|
||||
gpio_set_mode(GPIO_PORT(TACHO_PIN), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_PIN(TACHO_PIN)); // set tachometer pin to input
|
||||
rcc_periph_clock_enable(RCC_AFIO); // enable alternate function clock for external interrupt
|
||||
exti_select_source(GPIO_EXTI(TACHO_PIN), GPIO_PORT(TACHO_PIN)); // mask external interrupt of this pin only for this port
|
||||
gpio_set(GPIO_PORT(TACHO_PIN), GPIO_PIN(TACHO_PIN)); // pull up to eliminate noise
|
||||
exti_set_trigger(GPIO_EXTI(TACHO_PIN), EXTI_TRIGGER_FALLING); // trigger when opto-coupler triggers
|
||||
exti_enable_request(GPIO_EXTI(TACHO_PIN)); // enable external interrupt
|
||||
nvic_enable_irq(GPIO_NVIC_EXTI_IRQ(TACHO_PIN)); // enable interrupt
|
||||
printf("OK\n");
|
||||
|
||||
// load target tachometer value from EEPROM
|
||||
uint32_t eeprom_tacho[2];
|
||||
flash_internal_eeprom_setup(1); // use 1 page for EEPROM emulation
|
||||
bool eeprom_read = flash_internal_eeprom_read((uint8_t*)eeprom_tacho, sizeof(eeprom_tacho));
|
||||
printf("target tachometer count (");
|
||||
if (eeprom_read && eeprom_tacho[0] == (eeprom_tacho[1] ^ 0xffffffff)) {
|
||||
tacho_target = eeprom_tacho[0];
|
||||
printf("set");
|
||||
} else {
|
||||
tacho_target = TACHO_TARGET_DEFAULT;
|
||||
printf("default");
|
||||
}
|
||||
bool tacho_safety = false; // if the motor is switched of for safety reasons
|
||||
uint32_t tacho_activity = rtc_get_counter_val(); // when was the last time we saw the motor spinning
|
||||
printf("): %u\n", tacho_target);
|
||||
|
||||
// setup terminal
|
||||
terminal_prefix = ""; // set default prefix
|
||||
terminal_process = &process_command; // set central function to process commands
|
||||
@ -390,7 +468,6 @@ void main(void)
|
||||
|
||||
// start main loop
|
||||
bool action = false; // if an action has been performed don't go to sleep
|
||||
button_flag = false; // reset button flag
|
||||
while (true) { // infinite loop
|
||||
iwdg_reset(); // kick the dog
|
||||
if (user_input_available) { // user input is available
|
||||
@ -399,19 +476,32 @@ void main(void)
|
||||
char c = user_input_get(); // store receive character
|
||||
terminal_send(c); // send received character to terminal
|
||||
}
|
||||
if (button_flag) { // user pressed button
|
||||
action = true; // action has been performed
|
||||
printf("button pressed\n");
|
||||
led_toggle(); // toggle LED
|
||||
for (uint32_t i = 0; i < 1000000; i++) { // wait a bit to remove noise and double trigger
|
||||
__asm__("nop");
|
||||
}
|
||||
button_flag = false; // reset flag
|
||||
}
|
||||
if (rtc_internal_tick_flag) { // the internal RTC ticked
|
||||
rtc_internal_tick_flag = false; // reset flag
|
||||
action = true; // action has been performed
|
||||
uint32_t tacho = tacho_count; // backup before clearing
|
||||
tacho_count = 0; // restart count
|
||||
led_toggle(); // toggle LED (good to indicate if main function is stuck)
|
||||
if (!tacho_safety) {
|
||||
if (tacho < tacho_target) {
|
||||
gpio_clear(GPIO_PORT(SSR_PIN), GPIO_PIN(SSR_PIN)); // switch SSR on to provide power
|
||||
} else {
|
||||
gpio_set(GPIO_PORT(SSR_PIN), GPIO_PIN(SSR_PIN)); // switch SSR off to cut power
|
||||
}
|
||||
if (tacho) { // we tachometer indicates the motor is spinning
|
||||
tacho_activity = rtc_get_counter_val(); // updated the last time we saw it spinning
|
||||
} else if (rtc_get_counter_val() > tacho_activity + 5 * RTC_TICKS) { // the motor does not seem to turn, after 5 s
|
||||
tacho_safety = true; // turn safety on
|
||||
gpio_set(GPIO_PORT(SSR_PIN), GPIO_PIN(SSR_PIN)); // switch SSR off to cut power
|
||||
printf("\ntachometer does not indicate the motor is turning\n");
|
||||
printf("either the tachometer is defective, or the motor is stuck\n");
|
||||
printf("switching the motor off for safety\n");
|
||||
printf("reboot to retry\n");
|
||||
}
|
||||
}
|
||||
if (tacho_display) {
|
||||
printf("%u\n", tacho); // display tachometer frequency
|
||||
}
|
||||
}
|
||||
if (action) { // go to sleep if nothing had to be done, else recheck for activity
|
||||
action = false;
|
||||
@ -427,3 +517,10 @@ void rtc_isr(void)
|
||||
rtc_clear_flag(RTC_SEC); // clear flag
|
||||
rtc_internal_tick_flag = true; // notify to show new time
|
||||
}
|
||||
|
||||
/** interrupt service routine called when tachometer edge is detected is pressed */
|
||||
void GPIO_EXTI_ISR(TACHO_PIN)(void)
|
||||
{
|
||||
exti_reset_request(GPIO_EXTI(TACHO_PIN)); // reset interrupt
|
||||
tacho_count++; // increment edge count
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ PROVIDE(__flash_end = ORIGIN(rom) + LENGTH(rom));
|
||||
*/
|
||||
PROVIDE(__application_end = 0);
|
||||
PROVIDE(__flash_end = 0);
|
||||
|
||||
/* RAM location reserved so application can talk to bootloader and tell to start DFU */
|
||||
PROVIDE(__dfu_magic = ORIGIN(ram) - 4);
|
||||
|
||||
|
3
global.h
3
global.h
@ -665,6 +665,9 @@
|
||||
#elif defined (BLASTER)
|
||||
#define DFU_FORCE_PIN PA8 /**< GPIO pin (pin PA8, not SWD and UART pin on debug port) */
|
||||
#define DFU_FORCE_VALUE 0 /**< short to nearby ground connection to force DFU */
|
||||
#elif defined(STLINKV2)
|
||||
#define DFU_FORCE_PIN PB6 /**< RST pin pin */
|
||||
#define DFU_FORCE_VALUE 0 /**< short to nearby GND pin to force DFU */
|
||||
#elif defined(BUSVOODOO)
|
||||
#if BUSVOODOO_HARDWARE_VERSION==0
|
||||
/* on BusVoodoo v0 DFU input is on PC7 */
|
||||
|
@ -242,7 +242,7 @@ static char usb_serial[] = "00112233445566778899aabb";
|
||||
*/
|
||||
static const char* usb_strings[] = {
|
||||
"CuVoodoo", /**< manufacturer string */
|
||||
"CuVoodoo STM32F1xx firmware", /**< product string */
|
||||
"CuVoodoo dachboden clock jockey", /**< product string */
|
||||
(const char*)usb_serial, /**< device ID used as serial number */
|
||||
"DFU bootloader (runtime mode)", /**< DFU interface string */
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user