diff --git a/CHANGELOG b/CHANGELOG index 906b4e6c5..9d78a24d9 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,19 @@ +=== FW 3.66 === +* Added support for HW 100/250. +* Added uptime terminal command. +* Added some delays to DRV8323s SPI driver. +* Added SWD support for NRF52840 with idcode 0x015B. + - TODO: Have a look at https://github.com/blacksphere/blackmagic/commit/302ff20a6d5b806c09e0ca7e996beab3ef3596f4. +* Fixed INVERTED_SHUNT_POLARITY for BLDC. +* Added decoupling to FOC current controller. +* Better motor tracking at high ERPM and low Fsw. +* Made uart and permanent uart more independent. +* Do not write to USB if cable has not been connected. +* Added timeout to USB write. +* Better FOC current control integrator windup protection. +* Added FOC observer type selection options. +* Print TS5700N8501 position in encoder terminal command. + === FW 3.65 === * Added support for PTC motor temperature sensor (e.g. KTY84) * APP_PPM sleep fix. Should solve CAN issues. diff --git a/applications/app.h b/applications/app.h index 4bb02f439..1e81ea411 100644 --- a/applications/app.h +++ b/applications/app.h @@ -47,6 +47,7 @@ void app_uartcomm_start_permanent(void); void app_uartcomm_stop(void); void app_uartcomm_configure(uint32_t baudrate, bool permanent_enabled); void app_uartcomm_send_packet(unsigned char *data, unsigned int len); +void app_uartcomm_send_packet_p(unsigned char *data, unsigned int len); void app_nunchuk_start(void); void app_nunchuk_stop(void); diff --git a/applications/app_uartcomm.c b/applications/app_uartcomm.c index fb9f7e6ae..0d0fed354 100644 --- a/applications/app_uartcomm.c +++ b/applications/app_uartcomm.c @@ -41,10 +41,20 @@ static volatile bool uart_is_running = false; static mutex_t send_mutex; static bool send_mutex_init_done = false; +#ifdef HW_UART_P_DEV +static mutex_t send_mutex_p; +static bool send_mutex_p_init_done = false; +#endif + // Private functions static void process_packet(unsigned char *data, unsigned int len); static void send_packet(unsigned char *data, unsigned int len); +#ifdef HW_UART_P_DEV +static void process_packet_p(unsigned char *data, unsigned int len); +static void send_packet_p(unsigned char *data, unsigned int len); +#endif + static SerialConfig uart_cfg = { BAUDRATE, 0, @@ -67,27 +77,29 @@ static void process_packet(unsigned char *data, unsigned int len) { commands_process_packet(data, len, app_uartcomm_send_packet); } -static void send_packet(unsigned char *data, unsigned int len) { #ifdef HW_UART_P_DEV - if (from_p_uart) { - if (uart_p_is_running) { -#ifdef HW_UART_P_DEV_TX - sdWrite(&HW_UART_P_DEV_TX, data, len); -#else - sdWrite(&HW_UART_P_DEV, data, len); +static void process_packet_p(unsigned char *data, unsigned int len) { + commands_process_packet(data, len, app_uartcomm_send_packet_p); +} #endif - } - } else { - if (uart_is_running) { - sdWrite(&HW_UART_DEV, data, len); - } - } -#else + +static void send_packet(unsigned char *data, unsigned int len) { if (uart_is_running) { sdWrite(&HW_UART_DEV, data, len); } +} + +#ifdef HW_UART_P_DEV +static void send_packet_p(unsigned char *data, unsigned int len) { + if (uart_p_is_running) { +#ifdef HW_UART_P_DEV_TX + sdWrite(&HW_UART_P_DEV_TX, data, len); +#else + sdWrite(&HW_UART_P_DEV, data, len); #endif + } } +#endif void app_uartcomm_start(void) { packet_init(send_packet, process_packet, PACKET_HANDLER); @@ -111,8 +123,7 @@ void app_uartcomm_start(void) { void app_uartcomm_start_permanent(void) { #ifdef HW_UART_P_DEV - packet_init(send_packet, process_packet, PACKET_HANDLER); - packet_init(send_packet, process_packet, PACKET_HANDLER_P); + packet_init(send_packet_p, process_packet_p, PACKET_HANDLER_P); if (!thread_is_running) { chThdCreateStatic(packet_process_thread_wa, sizeof(packet_process_thread_wa), @@ -159,6 +170,22 @@ void app_uartcomm_send_packet(unsigned char *data, unsigned int len) { chMtxUnlock(&send_mutex); } +void app_uartcomm_send_packet_p(unsigned char *data, unsigned int len) { +#ifdef HW_UART_P_DEV + if (!send_mutex_p_init_done) { + chMtxObjectInit(&send_mutex_p); + send_mutex_p_init_done = true; + } + + chMtxLock(&send_mutex_p); + packet_send_packet(data, len, PACKET_HANDLER_P); + chMtxUnlock(&send_mutex_p); +#else + (void)data; + (void)len; +#endif +} + void app_uartcomm_configure(uint32_t baudrate, bool permanent_enabled) { uart_cfg.speed = baudrate; diff --git a/blackmagic/bm_if.c b/blackmagic/bm_if.c index fcf1e2b96..d1963e9ef 100644 --- a/blackmagic/bm_if.c +++ b/blackmagic/bm_if.c @@ -133,6 +133,7 @@ static int idcode_to_device(uint32_t idcode) { ret = 7; break; case 0x00EB: /* nRF52840 Preview QIAA AA0 */ case 0x0150: /* nRF52840 QIAA C0 */ + case 0x015B: /* nRF52840 ?? */ ret = 8; break; default: ret = -2; break; } @@ -362,6 +363,9 @@ int bm_connect(void) { if (cur_target) { ret = idcode_to_device(target_idcode(cur_target)); + if (ret < 0) { + commands_printf("Unknown idcode: 0x%04X\n", target_idcode(cur_target)); + } } } diff --git a/blackmagic/target/nrf51.c b/blackmagic/target/nrf51.c index ba3434cf2..1dab820d0 100644 --- a/blackmagic/target/nrf51.c +++ b/blackmagic/target/nrf51.c @@ -176,6 +176,7 @@ bool nrf51_probe(target *t) return true; case 0x00EB: /* nRF52840 Preview QIAA AA0 */ case 0x0150: /* nRF52840 QIAA C0 */ + case 0x015B: /* nRF52840 ?? */ t->driver = "Nordic nRF52"; target_add_ram(t, 0x20000000, 256*1024); nrf51_add_flash(t, 0x00000000, 1024*1024, NRF52_PAGE_SIZE); diff --git a/build_all/100_250/VESC_default.bin b/build_all/100_250/VESC_default.bin new file mode 100755 index 000000000..5c57ca1a1 Binary files /dev/null and b/build_all/100_250/VESC_default.bin differ diff --git a/build_all/100_250/VESC_default_no_hw_limits.bin b/build_all/100_250/VESC_default_no_hw_limits.bin new file mode 100755 index 000000000..a385f07a9 Binary files /dev/null and b/build_all/100_250/VESC_default_no_hw_limits.bin differ diff --git a/build_all/100_250/VESC_servoout.bin b/build_all/100_250/VESC_servoout.bin new file mode 100755 index 000000000..bf5e3ab65 Binary files /dev/null and b/build_all/100_250/VESC_servoout.bin differ diff --git a/build_all/410_o_411_o_412/VESC_0005ohm.bin b/build_all/410_o_411_o_412/VESC_0005ohm.bin index 47563c4e0..85af2cd42 100755 Binary files a/build_all/410_o_411_o_412/VESC_0005ohm.bin and b/build_all/410_o_411_o_412/VESC_0005ohm.bin differ diff --git a/build_all/410_o_411_o_412/VESC_default.bin b/build_all/410_o_411_o_412/VESC_default.bin index 24d1b60bb..dc82b183e 100755 Binary files a/build_all/410_o_411_o_412/VESC_default.bin and b/build_all/410_o_411_o_412/VESC_default.bin differ diff --git a/build_all/410_o_411_o_412/VESC_default_no_hw_limits.bin b/build_all/410_o_411_o_412/VESC_default_no_hw_limits.bin index 5b0ca14aa..eb55b70d0 100755 Binary files a/build_all/410_o_411_o_412/VESC_default_no_hw_limits.bin and b/build_all/410_o_411_o_412/VESC_default_no_hw_limits.bin differ diff --git a/build_all/410_o_411_o_412/VESC_servoout.bin b/build_all/410_o_411_o_412/VESC_servoout.bin index 43837d7fe..8f2b70715 100755 Binary files a/build_all/410_o_411_o_412/VESC_servoout.bin and b/build_all/410_o_411_o_412/VESC_servoout.bin differ diff --git a/build_all/410_o_411_o_412/VESC_ws2811.bin b/build_all/410_o_411_o_412/VESC_ws2811.bin index 0c74c545a..7a211f979 100755 Binary files a/build_all/410_o_411_o_412/VESC_ws2811.bin and b/build_all/410_o_411_o_412/VESC_ws2811.bin differ diff --git a/build_all/46_o_47/VESC_0005ohm.bin b/build_all/46_o_47/VESC_0005ohm.bin index e68e3b932..4e8f67fc5 100755 Binary files a/build_all/46_o_47/VESC_0005ohm.bin and b/build_all/46_o_47/VESC_0005ohm.bin differ diff --git a/build_all/46_o_47/VESC_33k.bin b/build_all/46_o_47/VESC_33k.bin index b5f8f1579..4e6554600 100755 Binary files a/build_all/46_o_47/VESC_33k.bin and b/build_all/46_o_47/VESC_33k.bin differ diff --git a/build_all/46_o_47/VESC_default.bin b/build_all/46_o_47/VESC_default.bin index 1315b6cea..764c1888c 100755 Binary files a/build_all/46_o_47/VESC_default.bin and b/build_all/46_o_47/VESC_default.bin differ diff --git a/build_all/46_o_47/VESC_servoout.bin b/build_all/46_o_47/VESC_servoout.bin index 6265f770b..96a13ee74 100755 Binary files a/build_all/46_o_47/VESC_servoout.bin and b/build_all/46_o_47/VESC_servoout.bin differ diff --git a/build_all/46_o_47/VESC_ws2811.bin b/build_all/46_o_47/VESC_ws2811.bin index 8dd7b1a75..0e0ca58bd 100755 Binary files a/build_all/46_o_47/VESC_ws2811.bin and b/build_all/46_o_47/VESC_ws2811.bin differ diff --git a/build_all/46_o_47/VESC_ws2811_33k.bin b/build_all/46_o_47/VESC_ws2811_33k.bin index 848e33f9e..63acb4a5e 100755 Binary files a/build_all/46_o_47/VESC_ws2811_33k.bin and b/build_all/46_o_47/VESC_ws2811_33k.bin differ diff --git a/build_all/48/VESC_0005ohm.bin b/build_all/48/VESC_0005ohm.bin index e533890d6..940ffa261 100755 Binary files a/build_all/48/VESC_0005ohm.bin and b/build_all/48/VESC_0005ohm.bin differ diff --git a/build_all/48/VESC_default.bin b/build_all/48/VESC_default.bin index 703c398da..9e44e8142 100755 Binary files a/build_all/48/VESC_default.bin and b/build_all/48/VESC_default.bin differ diff --git a/build_all/48/VESC_servoout.bin b/build_all/48/VESC_servoout.bin index a2b91ab66..ef060382a 100755 Binary files a/build_all/48/VESC_servoout.bin and b/build_all/48/VESC_servoout.bin differ diff --git a/build_all/48/VESC_ws2811.bin b/build_all/48/VESC_ws2811.bin index 9d907c5ac..424b13521 100755 Binary files a/build_all/48/VESC_ws2811.bin and b/build_all/48/VESC_ws2811.bin differ diff --git a/build_all/60/VESC_default.bin b/build_all/60/VESC_default.bin index 97abd413e..4c19ec78a 100755 Binary files a/build_all/60/VESC_default.bin and b/build_all/60/VESC_default.bin differ diff --git a/build_all/60/VESC_default_no_hw_limits.bin b/build_all/60/VESC_default_no_hw_limits.bin index f8f31f64f..d4525156f 100755 Binary files a/build_all/60/VESC_default_no_hw_limits.bin and b/build_all/60/VESC_default_no_hw_limits.bin differ diff --git a/build_all/60/VESC_servoout.bin b/build_all/60/VESC_servoout.bin index 8637365d5..43d6f0c92 100755 Binary files a/build_all/60/VESC_servoout.bin and b/build_all/60/VESC_servoout.bin differ diff --git a/build_all/60/VESC_ws2811.bin b/build_all/60/VESC_ws2811.bin index e702e542a..63685db9e 100755 Binary files a/build_all/60/VESC_ws2811.bin and b/build_all/60/VESC_ws2811.bin differ diff --git a/build_all/60_MK3/VESC_default.bin b/build_all/60_MK3/VESC_default.bin index 8ef97f322..fbcfffbeb 100755 Binary files a/build_all/60_MK3/VESC_default.bin and b/build_all/60_MK3/VESC_default.bin differ diff --git a/build_all/60_MK3/VESC_default_no_hw_limits.bin b/build_all/60_MK3/VESC_default_no_hw_limits.bin index a9553a9e0..b1c9b3c0f 100755 Binary files a/build_all/60_MK3/VESC_default_no_hw_limits.bin and b/build_all/60_MK3/VESC_default_no_hw_limits.bin differ diff --git a/build_all/60_MK3/VESC_servoout.bin b/build_all/60_MK3/VESC_servoout.bin index 4372c54c9..0e6cbd55f 100755 Binary files a/build_all/60_MK3/VESC_servoout.bin and b/build_all/60_MK3/VESC_servoout.bin differ diff --git a/build_all/60_MK3/VESC_ws2811.bin b/build_all/60_MK3/VESC_ws2811.bin index 07bb4bfc2..1da7bdd08 100755 Binary files a/build_all/60_MK3/VESC_ws2811.bin and b/build_all/60_MK3/VESC_ws2811.bin differ diff --git a/build_all/75_300/VESC_default.bin b/build_all/75_300/VESC_default.bin index da8b48dda..0f220e4e5 100755 Binary files a/build_all/75_300/VESC_default.bin and b/build_all/75_300/VESC_default.bin differ diff --git a/build_all/75_300/VESC_default_no_hw_limits.bin b/build_all/75_300/VESC_default_no_hw_limits.bin index 93daec04c..c99ac1f5c 100755 Binary files a/build_all/75_300/VESC_default_no_hw_limits.bin and b/build_all/75_300/VESC_default_no_hw_limits.bin differ diff --git a/build_all/75_300/VESC_servoout.bin b/build_all/75_300/VESC_servoout.bin index 12059f938..c04218696 100755 Binary files a/build_all/75_300/VESC_servoout.bin and b/build_all/75_300/VESC_servoout.bin differ diff --git a/build_all/75_300/VESC_ws2811.bin b/build_all/75_300/VESC_ws2811.bin index a770cbc26..f1c8af777 100755 Binary files a/build_all/75_300/VESC_ws2811.bin and b/build_all/75_300/VESC_ws2811.bin differ diff --git a/build_all/75_300_R2/VESC_default.bin b/build_all/75_300_R2/VESC_default.bin index 3b01be60d..9d7e641bb 100755 Binary files a/build_all/75_300_R2/VESC_default.bin and b/build_all/75_300_R2/VESC_default.bin differ diff --git a/build_all/75_300_R2/VESC_default_no_hw_limits.bin b/build_all/75_300_R2/VESC_default_no_hw_limits.bin index 89b376904..053169164 100755 Binary files a/build_all/75_300_R2/VESC_default_no_hw_limits.bin and b/build_all/75_300_R2/VESC_default_no_hw_limits.bin differ diff --git a/build_all/75_300_R2/VESC_servoout.bin b/build_all/75_300_R2/VESC_servoout.bin index 2d0ac95a1..565cba691 100755 Binary files a/build_all/75_300_R2/VESC_servoout.bin and b/build_all/75_300_R2/VESC_servoout.bin differ diff --git a/build_all/75_300_R2/VESC_ws2811.bin b/build_all/75_300_R2/VESC_ws2811.bin index f60eba429..349487e70 100755 Binary files a/build_all/75_300_R2/VESC_ws2811.bin and b/build_all/75_300_R2/VESC_ws2811.bin differ diff --git a/build_all/A200S_V21/VESC_default.bin b/build_all/A200S_V21/VESC_default.bin index 914ac0af8..faea4a135 100755 Binary files a/build_all/A200S_V21/VESC_default.bin and b/build_all/A200S_V21/VESC_default.bin differ diff --git a/build_all/A200S_V22/VESC_default.bin b/build_all/A200S_V22/VESC_default.bin index b612bbfff..7df23f1d2 100755 Binary files a/build_all/A200S_V22/VESC_default.bin and b/build_all/A200S_V22/VESC_default.bin differ diff --git a/build_all/AXIOM/VESC_default.bin b/build_all/AXIOM/VESC_default.bin index fa5342feb..fa8c79864 100755 Binary files a/build_all/AXIOM/VESC_default.bin and b/build_all/AXIOM/VESC_default.bin differ diff --git a/build_all/DAS_RS/VESC_default.bin b/build_all/DAS_RS/VESC_default.bin index bd2c8cf87..da7d09e41 100755 Binary files a/build_all/DAS_RS/VESC_default.bin and b/build_all/DAS_RS/VESC_default.bin differ diff --git a/build_all/HD/VESC_default.bin b/build_all/HD/VESC_default.bin index 0a0b0347a..89c9c7541 100755 Binary files a/build_all/HD/VESC_default.bin and b/build_all/HD/VESC_default.bin differ diff --git a/build_all/HD/VESC_default_no_hw_limits.bin b/build_all/HD/VESC_default_no_hw_limits.bin index d4518289b..7abcea0b4 100755 Binary files a/build_all/HD/VESC_default_no_hw_limits.bin and b/build_all/HD/VESC_default_no_hw_limits.bin differ diff --git a/build_all/HD/VESC_servoout.bin b/build_all/HD/VESC_servoout.bin index 9f4db064c..cea9b870a 100755 Binary files a/build_all/HD/VESC_servoout.bin and b/build_all/HD/VESC_servoout.bin differ diff --git a/build_all/HD/VESC_ws2811.bin b/build_all/HD/VESC_ws2811.bin index b535d50d7..03f3f0fce 100755 Binary files a/build_all/HD/VESC_ws2811.bin and b/build_all/HD/VESC_ws2811.bin differ diff --git a/build_all/UAVC_OMEGA/VESC_default.bin b/build_all/UAVC_OMEGA/VESC_default.bin index f0cf4b023..a62c4b796 100755 Binary files a/build_all/UAVC_OMEGA/VESC_default.bin and b/build_all/UAVC_OMEGA/VESC_default.bin differ diff --git a/build_all/rebuild_all b/build_all/rebuild_all index 883d6e4f1..08078505f 100755 --- a/build_all/rebuild_all +++ b/build_all/rebuild_all @@ -399,3 +399,34 @@ cd $FWPATH make clean cd $DIR +#################### HW 100_250 ######################## + +COPYDIR=100_250 +rm -f $COPYDIR/* + +# default +cd $FWPATH +touch conf_general.h +make -j8 build_args='-DHW_SOURCE=\"hw_100_250.c\" -DHW_HEADER=\"hw_100_250.h\"' USE_VERBOSE_COMPILE=no +cd $DIR +cp $FWPATH/build/BLDC_4_ChibiOS.bin $COPYDIR/VESC_default.bin + +# default with HW limits disables +cd $FWPATH +touch conf_general.h +make -j8 build_args='-DDISABLE_HW_LIMITS -DHW_SOURCE=\"hw_100_250.c\" -DHW_HEADER=\"hw_100_250.h\"' USE_VERBOSE_COMPILE=no +cd $DIR +cp $FWPATH/build/BLDC_4_ChibiOS.bin $COPYDIR/VESC_default_no_hw_limits.bin + +# servoout +cd $FWPATH +touch conf_general.h +make -j8 build_args='-DSERVO_OUT_ENABLE=1 -DHW_SOURCE=\"hw_100_250.c\" -DHW_HEADER=\"hw_100_250.h\"' USE_VERBOSE_COMPILE=no +cd $DIR +cp $FWPATH/build/BLDC_4_ChibiOS.bin $COPYDIR/VESC_servoout.bin + +# Clean +cd $FWPATH +make clean +cd $DIR + diff --git a/comm_usb.c b/comm_usb.c index 0935fa937..3944fb19c 100644 --- a/comm_usb.c +++ b/comm_usb.c @@ -32,10 +32,11 @@ static uint8_t serial_rx_buffer[SERIAL_RX_BUFFER_SIZE]; static int serial_rx_read_pos = 0; static int serial_rx_write_pos = 0; -static THD_WORKING_AREA(serial_read_thread_wa, 256); +static THD_WORKING_AREA(serial_read_thread_wa, 128); static THD_WORKING_AREA(serial_process_thread_wa, 4096); static mutex_t send_mutex; static thread_t *process_tp; +static volatile unsigned int write_timeout_cnt = 0; // Private functions static void process_packet(unsigned char *data, unsigned int len); @@ -44,9 +45,9 @@ static void send_packet_raw(unsigned char *buffer, unsigned int len); static THD_FUNCTION(serial_read_thread, arg) { (void)arg; - chRegSetThreadName("USB-Serial read"); + chRegSetThreadName("USB read"); - uint8_t buffer[128]; + uint8_t buffer[2]; int had_data = 0; for(;;) { @@ -72,7 +73,7 @@ static THD_FUNCTION(serial_read_thread, arg) { static THD_FUNCTION(serial_process_thread, arg) { (void)arg; - chRegSetThreadName("USB-Serial process"); + chRegSetThreadName("USB process"); process_tp = chThdGetSelfX(); @@ -94,7 +95,26 @@ static void process_packet(unsigned char *data, unsigned int len) { } static void send_packet_raw(unsigned char *buffer, unsigned int len) { - chSequentialStreamWrite(&SDU1, buffer, len); + static bool was_timeout = false; + + /* + * Only write to USB if the cable has been connected at least once. If a timeout occurs + * make sure that this call does not stall on the next call, as the timeout probably occured + * because noone is listening on the USB. + */ + if (comm_usb_serial_configured_cnt() > 0) { + unsigned int written = 0; + if (was_timeout) { + written = SDU1.vmt->writet(&SDU1, buffer, len, TIME_IMMEDIATE); + } else { + written = SDU1.vmt->writet(&SDU1, buffer, len, MS2ST(100)); + } + + was_timeout = written != len; + if (was_timeout) { + write_timeout_cnt++; + } + } } void comm_usb_init(void) { @@ -113,3 +133,7 @@ void comm_usb_send_packet(unsigned char *data, unsigned int len) { packet_send_packet(data, len, PACKET_HANDLER); chMtxUnlock(&send_mutex); } + +unsigned int comm_usb_get_write_timeout_cnt(void) { + return write_timeout_cnt; +} diff --git a/comm_usb.h b/comm_usb.h index 5ecf69544..2e539d193 100644 --- a/comm_usb.h +++ b/comm_usb.h @@ -25,5 +25,6 @@ // Functions void comm_usb_init(void); void comm_usb_send_packet(unsigned char *data, unsigned int len); +unsigned int comm_usb_get_write_timeout_cnt(void); #endif /* COMM_USB_H_ */ diff --git a/comm_usb_serial.c b/comm_usb_serial.c index 20dfcd84c..aea880c68 100644 --- a/comm_usb_serial.c +++ b/comm_usb_serial.c @@ -250,11 +250,12 @@ static const USBEndpointConfig ep2config = { NULL }; +static volatile int configured_cnt = 0; + /* * Handles the USB driver global events. */ static void usb_event(USBDriver *usbp, usbevent_t event) { - switch (event) { case USB_EVENT_RESET: return; @@ -273,6 +274,7 @@ static void usb_event(USBDriver *usbp, usbevent_t event) { sduConfigureHookI(&SDU1); chSysUnlockFromISR(); + configured_cnt++; return; case USB_EVENT_SUSPEND: return; @@ -331,3 +333,9 @@ void comm_usb_serial_init(void) { int comm_usb_serial_is_active(void) { return SDU1.config->usbp->state == USB_ACTIVE; } + +// Every time the USB cable is plugged in a configuration is done. Unfortunately +// I haven't found a way to detect when the USB cable gets unplugged. +int comm_usb_serial_configured_cnt(void) { + return configured_cnt; +} diff --git a/comm_usb_serial.h b/comm_usb_serial.h index bab2c3888..308326d2e 100644 --- a/comm_usb_serial.h +++ b/comm_usb_serial.h @@ -7,5 +7,6 @@ extern SerialUSBDriver SDU1; // Functions void comm_usb_serial_init(void); int comm_usb_serial_is_active(void); +int comm_usb_serial_configured_cnt(void); #endif /* COMM_USB_SERIAL_H_ */ diff --git a/conf_general.h b/conf_general.h index f33d90761..8aaf3d603 100644 --- a/conf_general.h +++ b/conf_general.h @@ -22,7 +22,7 @@ // Firmware version #define FW_VERSION_MAJOR 3 -#define FW_VERSION_MINOR 65 +#define FW_VERSION_MINOR 66 #include "datatypes.h" @@ -123,6 +123,9 @@ //#define HW_SOURCE "hw_rd2.c" //#define HW_HEADER "hw_rd2.h" + +//#define HW_SOURCE "hw_100_250.c" +//#define HW_HEADER "hw_100_250.h" #endif #ifndef HW_SOURCE diff --git a/confgenerator.c b/confgenerator.c index c4d4ae0da..0a8a88e0a 100644 --- a/confgenerator.c +++ b/confgenerator.c @@ -97,6 +97,8 @@ int32_t confgenerator_serialize_mcconf(uint8_t *buffer, const mc_configuration * buffer[ind++] = conf->foc_temp_comp; buffer_append_float32_auto(buffer, conf->foc_temp_comp_base_temp, &ind); buffer_append_float32_auto(buffer, conf->foc_current_filter_const, &ind); + buffer[ind++] = conf->foc_cc_decoupling; + buffer[ind++] = conf->foc_observer_type; buffer_append_int16(buffer, conf->gpd_buffer_notify_left, &ind); buffer_append_int16(buffer, conf->gpd_buffer_interpol, &ind); buffer_append_float32_auto(buffer, conf->gpd_current_filter_const, &ind); @@ -363,6 +365,8 @@ bool confgenerator_deserialize_mcconf(const uint8_t *buffer, mc_configuration *c conf->foc_temp_comp = buffer[ind++]; conf->foc_temp_comp_base_temp = buffer_get_float32_auto(buffer, &ind); conf->foc_current_filter_const = buffer_get_float32_auto(buffer, &ind); + conf->foc_cc_decoupling = buffer[ind++]; + conf->foc_observer_type = buffer[ind++]; conf->gpd_buffer_notify_left = buffer_get_int16(buffer, &ind); conf->gpd_buffer_interpol = buffer_get_int16(buffer, &ind); conf->gpd_current_filter_const = buffer_get_float32_auto(buffer, &ind); @@ -625,6 +629,8 @@ void confgenerator_set_defaults_mcconf(mc_configuration *conf) { conf->foc_temp_comp = MCCONF_FOC_TEMP_COMP; conf->foc_temp_comp_base_temp = MCCONF_FOC_TEMP_COMP_BASE_TEMP; conf->foc_current_filter_const = MCCONF_FOC_CURRENT_FILTER_CONST; + conf->foc_cc_decoupling = MCCONF_FOC_CC_DECOUPLING; + conf->foc_observer_type = MCCONF_FOC_OBSERVER_TYPE; conf->gpd_buffer_notify_left = MCCONF_GPD_BUFFER_NOTIFY_LEFT; conf->gpd_buffer_interpol = MCCONF_GPD_BUFFER_INTERPOL; conf->gpd_current_filter_const = MCCONF_GPD_CURRENT_FILTER_CONST; diff --git a/confgenerator.h b/confgenerator.h index d9b7778a8..01940a4c4 100644 --- a/confgenerator.h +++ b/confgenerator.h @@ -8,7 +8,7 @@ #include <stdbool.h> // Constants -#define MCCONF_SIGNATURE 2967846088 +#define MCCONF_SIGNATURE 1671830952 #define APPCONF_SIGNATURE 783041200 // Functions diff --git a/datatypes.h b/datatypes.h index 9eb42b47a..c3eceae28 100644 --- a/datatypes.h +++ b/datatypes.h @@ -85,6 +85,19 @@ typedef enum { MOTOR_TYPE_GPD } mc_motor_type; +// FOC current controller decoupling mode. +typedef enum { + FOC_CC_DECOUPLING_DISABLED = 0, + FOC_CC_DECOUPLING_CROSS, + FOC_CC_DECOUPLING_BEMF, + FOC_CC_DECOUPLING_CROSS_BEMF +} mc_foc_cc_decoupling_mode; + +typedef enum { + FOC_OBSERVER_ORTEGA_ORIGINAL = 0, + FOC_OBSERVER_ORTEGA_ITERATIVE +} mc_foc_observer_type; + typedef enum { FAULT_CODE_NONE = 0, FAULT_CODE_OVER_VOLTAGE, @@ -268,6 +281,8 @@ typedef struct { bool foc_temp_comp; float foc_temp_comp_base_temp; float foc_current_filter_const; + mc_foc_cc_decoupling_mode foc_cc_decoupling; + mc_foc_observer_type foc_observer_type; // GPDrive int gpd_buffer_notify_left; int gpd_buffer_interpol; diff --git a/encoder.c b/encoder.c index dd06a1f27..f18858d4a 100644 --- a/encoder.c +++ b/encoder.c @@ -80,7 +80,7 @@ static bool index_found = false; static uint32_t enc_counts = 10000; static encoder_mode mode = ENCODER_MODE_NONE; static float last_enc_angle = 0.0; -static uint16_t spi_val = 0; +static uint32_t spi_val = 0; static uint32_t spi_error_cnt = 0; static float spi_error_rate = 0.0; @@ -117,7 +117,7 @@ uint32_t encoder_spi_get_error_cnt(void) { return spi_error_cnt; } -uint16_t encoder_spi_get_val(void) { +uint32_t encoder_spi_get_val(void) { return spi_val; } @@ -523,7 +523,7 @@ bool encoder_index_found(void) { static void spi_transfer(uint16_t *in_buf, const uint16_t *out_buf, int length) { for (int i = 0;i < length;i++) { uint16_t send = out_buf ? out_buf[i] : 0xFFFF; - uint16_t recieve = 0; + uint16_t receive = 0; for (int bit = 0;bit < 16;bit++) { //palWritePad(HW_SPI_PORT_MOSI, HW_SPI_PIN_MOSI, send >> 15); @@ -543,9 +543,9 @@ static void spi_transfer(uint16_t *in_buf, const uint16_t *out_buf, int length) __NOP(); samples += palReadPad(SPI_SW_MISO_GPIO, SPI_SW_MISO_PIN); - recieve <<= 1; + receive <<= 1; if (samples > 2) { - recieve |= 1; + receive |= 1; } palClearPad(SPI_SW_SCK_GPIO, SPI_SW_SCK_PIN); @@ -553,7 +553,7 @@ static void spi_transfer(uint16_t *in_buf, const uint16_t *out_buf, int length) } if (in_buf) { - in_buf[i] = recieve; + in_buf[i] = receive; } } } @@ -672,6 +672,7 @@ static THD_FUNCTION(ts5700n8501_thread, arg) { if (reply_ind == 6 && crc == reply[reply_ind - 1]) { uint32_t pos = (uint32_t)reply[2] + ((uint32_t)reply[3] << 8) + ((uint32_t)reply[4] << 16); + spi_val = pos; last_enc_angle = (float)pos / 131072.0 * 360.0; UTILS_LP_FAST(spi_error_rate, 0.0, 1.0 / AS5047_SAMPLE_RATE_HZ); } else { diff --git a/encoder.h b/encoder.h index dd40783aa..4dd471871 100644 --- a/encoder.h +++ b/encoder.h @@ -37,7 +37,7 @@ void encoder_tim_isr(void); void encoder_set_counts(uint32_t counts); bool encoder_index_found(void); -uint16_t encoder_spi_get_val(void); +uint32_t encoder_spi_get_val(void); uint32_t encoder_spi_get_error_cnt(void); float encoder_spi_get_error_rate(void); uint32_t encoder_sincos_get_signal_below_min_error_cnt(void); diff --git a/halconf.h b/halconf.h index acb08b2b4..abbbf1ec6 100644 --- a/halconf.h +++ b/halconf.h @@ -306,7 +306,7 @@ * buffers. */ #if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__) -#define SERIAL_USB_BUFFERS_SIZE 256 +#define SERIAL_USB_BUFFERS_SIZE 1024 #endif /*===========================================================================*/ diff --git a/hwconf/drv8323s.c b/hwconf/drv8323s.c index 78cef275f..211d8354f 100644 --- a/hwconf/drv8323s.c +++ b/hwconf/drv8323s.c @@ -355,15 +355,19 @@ static void spi_transfer(uint16_t *in_buf, const uint16_t *out_buf, int length) palClearPad(DRV8323S_SCK_GPIO, DRV8323S_SCK_PIN); - int r1, r2, r3; - r1 = palReadPad(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN); + int samples = 0; + samples += palReadPad(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN); __NOP(); - r2 = palReadPad(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN); + samples += palReadPad(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN); __NOP(); - r3 = palReadPad(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN); + samples += palReadPad(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN); + __NOP(); + samples += palReadPad(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN); + __NOP(); + samples += palReadPad(DRV8323S_MISO_GPIO, DRV8323S_MISO_PIN); receive <<= 1; - if (utils_middle_of_3_int(r1, r2, r3)) { + if (samples > 2) { receive |= 1; } @@ -377,11 +381,15 @@ static void spi_transfer(uint16_t *in_buf, const uint16_t *out_buf, int length) } static void spi_begin(void) { + spi_delay(); palClearPad(DRV8323S_CS_GPIO, DRV8323S_CS_PIN); + spi_delay(); } static void spi_end(void) { + spi_delay(); palSetPad(DRV8323S_CS_GPIO, DRV8323S_CS_PIN); + spi_delay(); } static void spi_delay(void) { diff --git a/hwconf/hw.h b/hwconf/hw.h index 8722870b5..0c039a556 100644 --- a/hwconf/hw.h +++ b/hwconf/hw.h @@ -199,6 +199,18 @@ #define IS_DRV_FAULT() 0 #endif +// Double samples in beginning and end for positive current measurement. +// Useful when the shunt sense traces have noise that causes offset. +#ifndef CURR1_DOUBLE_SAMPLE +#define CURR1_DOUBLE_SAMPLE 0 +#endif +#ifndef CURR2_DOUBLE_SAMPLE +#define CURR2_DOUBLE_SAMPLE 0 +#endif +#ifndef CURR3_DOUBLE_SAMPLE +#define CURR3_DOUBLE_SAMPLE 0 +#endif + #ifndef AUX_ON #define AUX_ON() #endif diff --git a/hwconf/hw_100_250.c b/hwconf/hw_100_250.c new file mode 100644 index 000000000..836faad29 --- /dev/null +++ b/hwconf/hw_100_250.c @@ -0,0 +1,255 @@ +/* + Copyright 2018 Benjamin Vedder benjamin@vedder.se + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "hw.h" + +#include "ch.h" +#include "hal.h" +#include "stm32f4xx_conf.h" +#include "utils.h" +#include <math.h> +#include "mc_interface.h" + +// Variables +static volatile bool i2c_running = false; + +// I2C configuration +static const I2CConfig i2cfg = { + OPMODE_I2C, + 100000, + STD_DUTY_CYCLE +}; + +void hw_init_gpio(void) { + // GPIO clock enable + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); + RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); + + // LEDs + palSetPadMode(LED_GREEN_GPIO, LED_GREEN_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + palSetPadMode(LED_RED_GPIO, LED_RED_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + + // GPIOA Configuration: Channel 1 to 3 as alternate function push-pull + palSetPadMode(GPIOA, 8, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOA, 9, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOA, 10, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + + palSetPadMode(GPIOB, 13, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOB, 14, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + palSetPadMode(GPIOB, 15, PAL_MODE_ALTERNATE(GPIO_AF_TIM1) | + PAL_STM32_OSPEED_HIGHEST | + PAL_STM32_PUDR_FLOATING); + + // Hall sensors + palSetPadMode(HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1, PAL_MODE_INPUT_PULLUP); + palSetPadMode(HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2, PAL_MODE_INPUT_PULLUP); + palSetPadMode(HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3, PAL_MODE_INPUT_PULLUP); + + // Phase filters + palSetPadMode(PHASE_FILTER_GPIO, PHASE_FILTER_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + PHASE_FILTER_OFF(); + + // AUX pin + AUX_OFF(); + palSetPadMode(AUX_GPIO, AUX_PIN, + PAL_MODE_OUTPUT_PUSHPULL | + PAL_STM32_OSPEED_HIGHEST); + + // ADC Pins + palSetPadMode(GPIOA, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 1, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 2, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 3, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 5, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOA, 6, PAL_MODE_INPUT_ANALOG); + + palSetPadMode(GPIOB, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOB, 1, PAL_MODE_INPUT_ANALOG); + + palSetPadMode(GPIOC, 0, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 1, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 2, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 3, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 4, PAL_MODE_INPUT_ANALOG); + palSetPadMode(GPIOC, 5, PAL_MODE_INPUT_ANALOG); +} + +void hw_setup_adc_channels(void) { + // ADC1 regular channels + ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 2, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 3, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 4, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC1, ADC_Channel_Vrefint, 5, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC1, ADC_Channel_8, 6, ADC_SampleTime_15Cycles); + + // ADC2 regular channels + ADC_RegularChannelConfig(ADC2, ADC_Channel_1, 1, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC2, ADC_Channel_6, 3, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC2, ADC_Channel_15, 4, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC2, ADC_Channel_0, 5, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 6, ADC_SampleTime_15Cycles); + + // ADC3 regular channels + ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 1, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC3, ADC_Channel_12, 2, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC3, ADC_Channel_3, 3, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC3, ADC_Channel_13, 4, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC3, ADC_Channel_1, 5, ADC_SampleTime_15Cycles); + ADC_RegularChannelConfig(ADC3, ADC_Channel_2, 6, ADC_SampleTime_15Cycles); + + // Injected channels + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 1, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 2, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 2, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 2, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC1, ADC_Channel_10, 3, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC2, ADC_Channel_11, 3, ADC_SampleTime_15Cycles); + ADC_InjectedChannelConfig(ADC3, ADC_Channel_12, 3, ADC_SampleTime_15Cycles); +} + +void hw_start_i2c(void) { + i2cAcquireBus(&HW_I2C_DEV); + + if (!i2c_running) { + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + i2cStart(&HW_I2C_DEV, &i2cfg); + i2c_running = true; + } + + i2cReleaseBus(&HW_I2C_DEV); +} + +void hw_stop_i2c(void) { + i2cAcquireBus(&HW_I2C_DEV); + + if (i2c_running) { + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, PAL_MODE_INPUT); + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, PAL_MODE_INPUT); + + i2cStop(&HW_I2C_DEV); + i2c_running = false; + + } + + i2cReleaseBus(&HW_I2C_DEV); +} + +/** + * Try to restore the i2c bus + */ +void hw_try_restore_i2c(void) { + if (i2c_running) { + i2cAcquireBus(&HW_I2C_DEV); + + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + palSetPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + + chThdSleep(1); + + for(int i = 0;i < 16;i++) { + palClearPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + } + + // Generate start then stop condition + palClearPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + chThdSleep(1); + palClearPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN); + chThdSleep(1); + palSetPad(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN); + + palSetPadMode(HW_I2C_SCL_PORT, HW_I2C_SCL_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + palSetPadMode(HW_I2C_SDA_PORT, HW_I2C_SDA_PIN, + PAL_MODE_ALTERNATE(HW_I2C_GPIO_AF) | + PAL_STM32_OTYPE_OPENDRAIN | + PAL_STM32_OSPEED_MID1 | + PAL_STM32_PUDR_PULLUP); + + HW_I2C_DEV.state = I2C_STOP; + i2cStart(&HW_I2C_DEV, &i2cfg); + + i2cReleaseBus(&HW_I2C_DEV); + } +} + +float hw100_250_get_temp(void) { + float t1 = (1.0 / ((logf(NTC_RES(ADC_Value[ADC_IND_TEMP_MOS]) / 10000.0) / 3380.0) + (1.0 / 298.15)) - 273.15); + float t2 = (1.0 / ((logf(NTC_RES(ADC_Value[ADC_IND_TEMP_MOS_2]) / 10000.0) / 3380.0) + (1.0 / 298.15)) - 273.15); + float t3 = (1.0 / ((logf(NTC_RES(ADC_Value[ADC_IND_TEMP_MOS_3]) / 10000.0) / 3380.0) + (1.0 / 298.15)) - 273.15); + float res = 0.0; + + if (t1 > t2 && t1 > t3) { + res = t1; + } else if (t2 > t1 && t2 > t3) { + res = t2; + } else { + res = t3; + } + + return res; +} diff --git a/hwconf/hw_100_250.h b/hwconf/hw_100_250.h new file mode 100644 index 000000000..731c49fdc --- /dev/null +++ b/hwconf/hw_100_250.h @@ -0,0 +1,260 @@ +/* + Copyright 2018 Benjamin Vedder benjamin@vedder.se + + This file is part of the VESC firmware. + + The VESC firmware is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + The VESC firmware is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef HW_100_250_H_ +#define HW_100_250_H_ + +#define HW_NAME "100_250" + +// HW properties +#define HW_HAS_3_SHUNTS +#define INVERTED_SHUNT_POLARITY + +// Macros +#define LED_GREEN_GPIO GPIOB +#define LED_GREEN_PIN 5 +#define LED_RED_GPIO GPIOB +#define LED_RED_PIN 7 + +#define LED_GREEN_ON() palSetPad(LED_GREEN_GPIO, LED_GREEN_PIN) +#define LED_GREEN_OFF() palClearPad(LED_GREEN_GPIO, LED_GREEN_PIN) +#define LED_RED_ON() palSetPad(LED_RED_GPIO, LED_RED_PIN) +#define LED_RED_OFF() palClearPad(LED_RED_GPIO, LED_RED_PIN) + +#define PHASE_FILTER_GPIO GPIOC +#define PHASE_FILTER_PIN 9 +#define PHASE_FILTER_ON() palSetPad(PHASE_FILTER_GPIO, PHASE_FILTER_PIN) +#define PHASE_FILTER_OFF() palClearPad(PHASE_FILTER_GPIO, PHASE_FILTER_PIN) + +#define AUX_GPIO GPIOC +#define AUX_PIN 12 +#define AUX_ON() palSetPad(AUX_GPIO, AUX_PIN) +#define AUX_OFF() palClearPad(AUX_GPIO, AUX_PIN) + +/* + * ADC Vector + * + * 0 (1): IN0 SENS1 + * 1 (2): IN1 SENS2 + * 2 (3): IN2 SENS3 + * 3 (1): IN10 CURR1 + * 4 (2): IN11 CURR2 + * 5 (3): IN12 CURR3 + * 6 (1): IN5 ADC_EXT1 + * 7 (2): IN6 ADC_EXT2 + * 8 (3): IN3 TEMP_MOS + * 9 (1): IN14 TEMP_MOTOR + * 10 (2): IN15 ADC_EXT3 + * 11 (3): IN13 AN_IN + * 12 (1): Vrefint + * 13 (2): IN0 SENS1 + * 14 (3): IN1 SENS2 + * 15 (1): IN8 TEMP_MOS_2 + * 16 (2): IN9 TEMP_MOS_3 + * 17 (3): IN3 SENS3 + */ + +#define HW_ADC_CHANNELS 18 +#define HW_ADC_INJ_CHANNELS 3 +#define HW_ADC_NBR_CONV 6 + +// ADC Indexes +#define ADC_IND_SENS1 0 +#define ADC_IND_SENS2 1 +#define ADC_IND_SENS3 2 +#define ADC_IND_CURR1 3 +#define ADC_IND_CURR2 4 +#define ADC_IND_CURR3 5 +#define ADC_IND_VIN_SENS 11 +#define ADC_IND_EXT 6 +#define ADC_IND_EXT2 7 +#define ADC_IND_EXT3 10 +#define ADC_IND_TEMP_MOS 8 +#define ADC_IND_TEMP_MOS_2 15 +#define ADC_IND_TEMP_MOS_3 16 +#define ADC_IND_TEMP_MOTOR 9 +#define ADC_IND_VREFINT 12 + +// ADC macros and settings + +// Component parameters (can be overridden) +#ifndef V_REG +#define V_REG 3.44 +#endif +#ifndef VIN_R1 +#define VIN_R1 150000.0 +#endif +#ifndef VIN_R2 +#define VIN_R2 4700.0 +#endif +#ifndef CURRENT_AMP_GAIN +#define CURRENT_AMP_GAIN 20.0 +#endif +#ifndef CURRENT_SHUNT_RES +#define CURRENT_SHUNT_RES (0.0005 / 3.0) +#endif + +// Input voltage +#define GET_INPUT_VOLTAGE() ((V_REG / 4095.0) * (float)ADC_Value[ADC_IND_VIN_SENS] * ((VIN_R1 + VIN_R2) / VIN_R2)) + +// NTC Termistors +#define NTC_RES(adc_val) ((4095.0 * 10000.0) / adc_val - 10000.0) +#define NTC_TEMP(adc_ind) hw100_250_get_temp() + +#define NTC_RES_MOTOR(adc_val) (10000.0 / ((4095.0 / (float)adc_val) - 1.0)) // Motor temp sensor on low side +#define NTC_TEMP_MOTOR(beta) (1.0 / ((logf(NTC_RES_MOTOR(ADC_Value[ADC_IND_TEMP_MOTOR]) / 10000.0) / beta) + (1.0 / 298.15)) - 273.15) + +#define NTC_TEMP_MOS1() (1.0 / ((logf(NTC_RES(ADC_Value[ADC_IND_TEMP_MOS]) / 10000.0) / 3380.0) + (1.0 / 298.15)) - 273.15) +#define NTC_TEMP_MOS2() (1.0 / ((logf(NTC_RES(ADC_Value[ADC_IND_TEMP_MOS_2]) / 10000.0) / 3380.0) + (1.0 / 298.15)) - 273.15) +#define NTC_TEMP_MOS3() (1.0 / ((logf(NTC_RES(ADC_Value[ADC_IND_TEMP_MOS_3]) / 10000.0) / 3380.0) + (1.0 / 298.15)) - 273.15) + +// Voltage on ADC channel +#define ADC_VOLTS(ch) ((float)ADC_Value[ch] / 4096.0 * V_REG) + +// COMM-port ADC GPIOs +#define HW_ADC_EXT_GPIO GPIOA +#define HW_ADC_EXT_PIN 5 +#define HW_ADC_EXT2_GPIO GPIOA +#define HW_ADC_EXT2_PIN 6 + +// UART Peripheral +#define HW_UART_DEV SD3 +#define HW_UART_GPIO_AF GPIO_AF_USART3 +#define HW_UART_TX_PORT GPIOB +#define HW_UART_TX_PIN 10 +#define HW_UART_RX_PORT GPIOB +#define HW_UART_RX_PIN 11 + +// Permanent UART Peripheral (for NRF52) +#define HW_UART_P_BAUD 115200 +#define HW_UART_P_DEV SD4 +#define HW_UART_P_GPIO_AF GPIO_AF_UART4 +#define HW_UART_P_TX_PORT GPIOC +#define HW_UART_P_TX_PIN 10 +#define HW_UART_P_RX_PORT GPIOC +#define HW_UART_P_RX_PIN 11 + +// ICU Peripheral for servo decoding +#define HW_USE_SERVO_TIM4 +#define HW_ICU_TIMER TIM4 +#define HW_ICU_TIM_CLK_EN() RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE) +#define HW_ICU_DEV ICUD4 +#define HW_ICU_CHANNEL ICU_CHANNEL_1 +#define HW_ICU_GPIO_AF GPIO_AF_TIM4 +#define HW_ICU_GPIO GPIOB +#define HW_ICU_PIN 6 + +// I2C Peripheral +#define HW_I2C_DEV I2CD2 +#define HW_I2C_GPIO_AF GPIO_AF_I2C2 +#define HW_I2C_SCL_PORT GPIOB +#define HW_I2C_SCL_PIN 10 +#define HW_I2C_SDA_PORT GPIOB +#define HW_I2C_SDA_PIN 11 + +// Hall/encoder pins +#define HW_HALL_ENC_GPIO1 GPIOC +#define HW_HALL_ENC_PIN1 6 +#define HW_HALL_ENC_GPIO2 GPIOC +#define HW_HALL_ENC_PIN2 7 +#define HW_HALL_ENC_GPIO3 GPIOC +#define HW_HALL_ENC_PIN3 8 +#define HW_ENC_TIM TIM3 +#define HW_ENC_TIM_AF GPIO_AF_TIM3 +#define HW_ENC_TIM_CLK_EN() RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE) +#define HW_ENC_EXTI_PORTSRC EXTI_PortSourceGPIOC +#define HW_ENC_EXTI_PINSRC EXTI_PinSource8 +#define HW_ENC_EXTI_CH EXTI9_5_IRQn +#define HW_ENC_EXTI_LINE EXTI_Line8 +#define HW_ENC_EXTI_ISR_VEC EXTI9_5_IRQHandler +#define HW_ENC_TIM_ISR_CH TIM3_IRQn +#define HW_ENC_TIM_ISR_VEC TIM3_IRQHandler + +// SPI pins +#define HW_SPI_DEV SPID1 +#define HW_SPI_GPIO_AF GPIO_AF_SPI1 +#define HW_SPI_PORT_NSS GPIOA +#define HW_SPI_PIN_NSS 4 +#define HW_SPI_PORT_SCK GPIOA +#define HW_SPI_PIN_SCK 5 +#define HW_SPI_PORT_MOSI GPIOA +#define HW_SPI_PIN_MOSI 7 +#define HW_SPI_PORT_MISO GPIOA +#define HW_SPI_PIN_MISO 6 + +// NRF SWD +#define NRF5x_SWDIO_GPIO GPIOA +#define NRF5x_SWDIO_PIN 15 +#define NRF5x_SWCLK_GPIO GPIOB +#define NRF5x_SWCLK_PIN 3 + +// Measurement macros +#define ADC_V_L1 ADC_Value[ADC_IND_SENS1] +#define ADC_V_L2 ADC_Value[ADC_IND_SENS2] +#define ADC_V_L3 ADC_Value[ADC_IND_SENS3] +#define ADC_V_ZERO (ADC_Value[ADC_IND_VIN_SENS] / 2) + +// Macros +#define READ_HALL1() palReadPad(HW_HALL_ENC_GPIO1, HW_HALL_ENC_PIN1) +#define READ_HALL2() palReadPad(HW_HALL_ENC_GPIO2, HW_HALL_ENC_PIN2) +#define READ_HALL3() palReadPad(HW_HALL_ENC_GPIO3, HW_HALL_ENC_PIN3) + +// Override dead time. See the stm32f4 reference manual for calculating this value. +#define HW_DEAD_TIME_NSEC 660.0 + +// Default setting overrides +#ifndef MCCONF_L_MIN_VOLTAGE +#define MCCONF_L_MIN_VOLTAGE 12.0 // Minimum input voltage +#endif +#ifndef MCCONF_L_MAX_VOLTAGE +#define MCCONF_L_MAX_VOLTAGE 96.0 // Maximum input voltage +#endif +#ifndef MCCONF_DEFAULT_MOTOR_TYPE +#define MCCONF_DEFAULT_MOTOR_TYPE MOTOR_TYPE_FOC +#endif +#ifndef MCCONF_FOC_F_SW +#define MCCONF_FOC_F_SW 30000.0 +#endif +#ifndef MCCONF_L_MAX_ABS_CURRENT +#define MCCONF_L_MAX_ABS_CURRENT 400.0 // The maximum absolute current above which a fault is generated +#endif +#ifndef MCCONF_FOC_SAMPLE_V0_V7 +#define MCCONF_FOC_SAMPLE_V0_V7 false // Run control loop in both v0 and v7 (requires phase shunts) +#endif +#ifndef MCCONF_L_IN_CURRENT_MAX +#define MCCONF_L_IN_CURRENT_MAX 250.0 // Input current limit in Amperes (Upper) +#endif +#ifndef MCCONF_L_IN_CURRENT_MIN +#define MCCONF_L_IN_CURRENT_MIN -200.0 // Input current limit in Amperes (Lower) +#endif + +// Setting limits +#define HW_LIM_CURRENT -300.0, 300.0 +#define HW_LIM_CURRENT_IN -300.0, 300.0 +#define HW_LIM_CURRENT_ABS 0.0, 420.0 +#define HW_LIM_VIN 11.0, 97.0 +#define HW_LIM_ERPM -200e3, 200e3 +#define HW_LIM_DUTY_MIN 0.0, 0.1 +#define HW_LIM_DUTY_MAX 0.0, 0.99 +#define HW_LIM_TEMP_FET -40.0, 110.0 + +// HW-specific functions +float hw100_250_get_temp(void); + +#endif /* HW_100_250_H_ */ diff --git a/hwconf/hw_75_300.h b/hwconf/hw_75_300.h index c1889c25e..5534259d7 100644 --- a/hwconf/hw_75_300.h +++ b/hwconf/hw_75_300.h @@ -260,6 +260,9 @@ #define HW_DEAD_TIME_NSEC 660.0 // Default setting overrides +#ifndef MCCONF_L_MIN_VOLTAGE +#define MCCONF_L_MIN_VOLTAGE 12.0 // Minimum input voltage +#endif #ifndef MCCONF_L_MAX_VOLTAGE #define MCCONF_L_MAX_VOLTAGE 72.0 // Maximum input voltage #endif @@ -283,10 +286,10 @@ #endif // Setting limits -#define HW_LIM_CURRENT -300.0, 300.0 -#define HW_LIM_CURRENT_IN -300.0, 300.0 -#define HW_LIM_CURRENT_ABS 0.0, 450.0 -#define HW_LIM_VIN 6.0, 72.0 +#define HW_LIM_CURRENT -400.0, 400.0 +#define HW_LIM_CURRENT_IN -400.0, 400.0 +#define HW_LIM_CURRENT_ABS 0.0, 480.0 +#define HW_LIM_VIN 11.0, 72.0 #define HW_LIM_ERPM -200e3, 200e3 #define HW_LIM_DUTY_MIN 0.0, 0.1 #define HW_LIM_DUTY_MAX 0.0, 0.99 diff --git a/mcconf/mcconf_default.h b/mcconf/mcconf_default.h index ac0771657..bc3f6ae1e 100644 --- a/mcconf/mcconf_default.h +++ b/mcconf/mcconf_default.h @@ -225,10 +225,10 @@ #define MCCONF_FOC_CURRENT_KI 50.0 #endif #ifndef MCCONF_FOC_F_SW -#define MCCONF_FOC_F_SW 20000.0 +#define MCCONF_FOC_F_SW 25000.0 #endif #ifndef MCCONF_FOC_DT_US -#define MCCONF_FOC_DT_US 0.08 // Microseconds for dead time compensation +#define MCCONF_FOC_DT_US 0.12 // Microseconds for dead time compensation #endif #ifndef MCCONF_FOC_ENCODER_INVERTED #define MCCONF_FOC_ENCODER_INVERTED false @@ -329,10 +329,16 @@ #ifndef MCCONF_FOC_CURRENT_FILTER_CONST #define MCCONF_FOC_CURRENT_FILTER_CONST 0.1 // Filter constant for the filtered currents #endif +#ifndef MCCONF_FOC_CC_DECOUPLING +#define MCCONF_FOC_CC_DECOUPLING FOC_CC_DECOUPLING_BEMF // Current controller decoupling +#endif +#ifndef MCCONF_FOC_OBSERVER_TYPE +#define MCCONF_FOC_OBSERVER_TYPE FOC_OBSERVER_ORTEGA_ORIGINAL // Position observer type for FOC +#endif // GPD #ifndef MCCONF_GPD_BUFFER_NOTIFY_LEFT -#define MCCONF_GPD_BUFFER_NOTIFY_LEFT 200 // Notify when the buffer space is left than this +#define MCCONF_GPD_BUFFER_NOTIFY_LEFT 200 // Notify when the buffer space left is less than this #endif #ifndef MCCONF_GPD_BUFFER_INTERPOL #define MCCONF_GPD_BUFFER_INTERPOL 0 // Buffer interpolation diff --git a/mcpwm.c b/mcpwm.c index 8780082af..a9fc7af23 100644 --- a/mcpwm.c +++ b/mcpwm.c @@ -1467,6 +1467,17 @@ void mcpwm_adc_inj_int_handler(void) { int curr2 = ADC_GetInjectedConversionValue(ADC3, ADC_InjectedChannel_1); #endif +#ifdef INVERTED_SHUNT_POLARITY + curr0 = 4095 - curr0; + curr1 = 4095 - curr1; + + curr0_2 = 4095 - curr0_2; + curr1_2 = 4095 - curr1_2; +#ifdef HW_HAS_3_SHUNTS + curr2 = 4095 - curr2; +#endif +#endif + float curr0_currsamp = curr0; float curr1_currsamp = curr1; #ifdef HW_HAS_3_SHUNTS diff --git a/mcpwm_foc.c b/mcpwm_foc.c index 2b0b413d6..348d9e1c2 100644 --- a/mcpwm_foc.c +++ b/mcpwm_foc.c @@ -64,6 +64,7 @@ typedef struct { float vq; float vd_int; float vq_int; + float speed_rad_s; uint32_t svm_sector; } motor_state_t; @@ -825,7 +826,7 @@ bool mcpwm_foc_is_using_encoder(void) { * The RPM value. */ float mcpwm_foc_get_rpm(void) { - return m_pll_speed / ((2.0 * M_PI) / 60.0); + return m_motor_state.speed_rad_s / ((2.0 * M_PI) / 60.0); } /** @@ -1987,6 +1988,8 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { observer_update(m_motor_state.v_alpha, m_motor_state.v_beta, m_motor_state.i_alpha, m_motor_state.i_beta, dt, &m_observer_x1, &m_observer_x2, &m_phase_now_observer); + m_phase_now_observer += m_pll_speed * dt * 0.5; + utils_norm_angle_rad((float*)&m_phase_now_observer); } switch (m_conf->foc_sensor_mode) { @@ -2073,6 +2076,17 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { control_current(&m_motor_state, dt); } else { + // The current is 0 when the motor is undriven + m_motor_state.i_alpha = 0.0; + m_motor_state.i_beta = 0.0; + m_motor_state.id = 0.0; + m_motor_state.iq = 0.0; + m_motor_state.id_filter = 0.0; + m_motor_state.iq_filter = 0.0; + m_motor_state.i_bus = 0.0; + m_motor_state.i_abs = 0.0; + m_motor_state.i_abs_filter = 0.0; + // Track back emf #ifdef HW_HAS_3_SHUNTS float Va = ADC_VOLTS(ADC_IND_SENS1) * ((VIN_R1 + VIN_R2) / VIN_R2); @@ -2088,9 +2102,6 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { m_motor_state.v_alpha = (2.0 / 3.0) * Va - (1.0 / 3.0) * Vb - (1.0 / 3.0) * Vc; m_motor_state.v_beta = ONE_BY_SQRT3 * Vb - ONE_BY_SQRT3 * Vc; - float c, s; - utils_fast_sincos_better(m_motor_state.phase, &s, &c); - #ifdef HW_USE_LINE_TO_LINE // rotate alpha-beta 30 degrees to compensate for line-to-line phase voltage sensing float x_tmp = m_motor_state.v_alpha; @@ -2104,38 +2115,16 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { m_motor_state.v_beta *= ONE_BY_SQRT3; #endif - // Park transform - float vd_tmp = c * m_motor_state.v_alpha + s * m_motor_state.v_beta; - float vq_tmp = c * m_motor_state.v_beta - s * m_motor_state.v_alpha; - - UTILS_NAN_ZERO(m_motor_state.vd); - UTILS_NAN_ZERO(m_motor_state.vq); - - UTILS_LP_FAST(m_motor_state.vd, vd_tmp, 0.2); - UTILS_LP_FAST(m_motor_state.vq, vq_tmp, 0.2); - - m_motor_state.vd_int = m_motor_state.vd; - m_motor_state.vq_int = m_motor_state.vq; - - // Update corresponding modulation - m_motor_state.mod_d = m_motor_state.vd / ((2.0 / 3.0) * m_motor_state.v_bus); - m_motor_state.mod_q = m_motor_state.vq / ((2.0 / 3.0) * m_motor_state.v_bus); - - // The current is 0 when the motor is undriven - m_motor_state.i_alpha = 0.0; - m_motor_state.i_beta = 0.0; - m_motor_state.id = 0.0; - m_motor_state.iq = 0.0; - m_motor_state.id_filter = 0.0; - m_motor_state.iq_filter = 0.0; - m_motor_state.i_bus = 0.0; - m_motor_state.i_abs = 0.0; - m_motor_state.i_abs_filter = 0.0; - // Run observer + static float x1_prev = 0.0; + static float x2_prev = 0.0; observer_update(m_motor_state.v_alpha, m_motor_state.v_beta, m_motor_state.i_alpha, m_motor_state.i_beta, dt, &m_observer_x1, - &m_observer_x2, &m_phase_now_observer); + &m_observer_x2, 0); + m_phase_now_observer = utils_fast_atan2(x2_prev + m_observer_x2, x1_prev + m_observer_x1); + + x1_prev = m_observer_x1; + x2_prev = m_observer_x2; switch (m_conf->foc_sensor_mode) { case FOC_SENSOR_MODE_ENCODER: @@ -2149,15 +2138,43 @@ void mcpwm_foc_adc_int_handler(void *p, uint32_t flags) { m_motor_state.phase = m_phase_now_observer; break; } + + float c, s; + utils_fast_sincos_better(m_motor_state.phase, &s, &c); + + // Park transform + float vd_tmp = c * m_motor_state.v_alpha + s * m_motor_state.v_beta; + float vq_tmp = c * m_motor_state.v_beta - s * m_motor_state.v_alpha; + + UTILS_NAN_ZERO(m_motor_state.vd); + UTILS_NAN_ZERO(m_motor_state.vq); + + UTILS_LP_FAST(m_motor_state.vd, vd_tmp, 0.2); + UTILS_LP_FAST(m_motor_state.vq, vq_tmp, 0.2); + + // Set the current controller integrator to the BEMF voltage to avoid + // a current spike when the motor is driven again. Notice that we have + // to take decoupling into account. + m_motor_state.vd_int = m_motor_state.vd; + m_motor_state.vq_int = m_motor_state.vq; + + if (m_conf->foc_cc_decoupling == FOC_CC_DECOUPLING_BEMF || m_conf->foc_cc_decoupling == FOC_CC_DECOUPLING_CROSS_BEMF) { + m_motor_state.vq_int -= m_motor_state.speed_rad_s * m_conf->foc_motor_flux_linkage; + } + + // Update corresponding modulation + m_motor_state.mod_d = m_motor_state.vd / ((2.0 / 3.0) * m_motor_state.v_bus); + m_motor_state.mod_q = m_motor_state.vq / ((2.0 / 3.0) * m_motor_state.v_bus); } // Calculate duty cycle m_motor_state.duty_now = SIGN(m_motor_state.vq) * - sqrtf(m_motor_state.mod_d * m_motor_state.mod_d + - m_motor_state.mod_q * m_motor_state.mod_q) / SQRT3_BY_2; + sqrtf(SQ(m_motor_state.mod_d) + SQ(m_motor_state.mod_q)) + / SQRT3_BY_2; // Run PLL for speed estimation pll_run(m_motor_state.phase, dt, &m_pll_phase, &m_pll_speed); + m_motor_state.speed_rad_s = m_pll_speed; // Update tachometer (resolution = 60 deg as for BLDC) float ph_tmp = m_motor_state.phase; @@ -2344,7 +2361,6 @@ void observer_update(float v_alpha, float v_beta, float i_alpha, float i_beta, float dt, volatile float *x1, volatile float *x2, volatile float *phase) { const float L = (3.0 / 2.0) * m_conf->foc_motor_l; - const float lambda = m_conf->foc_motor_flux_linkage; float R = (3.0 / 2.0) * m_conf->foc_motor_r; // Saturation compensation @@ -2353,7 +2369,7 @@ void observer_update(float v_alpha, float v_beta, float i_alpha, float i_beta, // Temperature compensation const float t = mc_interface_temp_motor_filtered(); - if (m_conf->foc_temp_comp && t > -5.0) { + if (m_conf->foc_temp_comp && t > -25.0) { R += R * 0.00386 * (t - m_conf->foc_temp_comp_base_temp); } @@ -2361,33 +2377,41 @@ void observer_update(float v_alpha, float v_beta, float i_alpha, float i_beta, const float L_ib = L * i_beta; const float R_ia = R * i_alpha; const float R_ib = R * i_beta; - const float lambda_2 = SQ(lambda); + const float lambda_2 = SQ(m_conf->foc_motor_flux_linkage); const float gamma_half = m_gamma_now * 0.5; - // Original -// float err = lambda_2 - (SQ(*x1 - L_ia) + SQ(*x2 - L_ib)); -// float x1_dot = -R_ia + v_alpha + gamma_half * (*x1 - L_ia) * err; -// float x2_dot = -R_ib + v_beta + gamma_half * (*x2 - L_ib) * err; -// *x1 += x1_dot * dt; -// *x2 += x2_dot * dt; + switch (m_conf->foc_observer_type) { + case FOC_OBSERVER_ORTEGA_ORIGINAL: { + float err = lambda_2 - (SQ(*x1 - L_ia) + SQ(*x2 - L_ib)); + float x1_dot = -R_ia + v_alpha + gamma_half * (*x1 - L_ia) * err; + float x2_dot = -R_ib + v_beta + gamma_half * (*x2 - L_ib) * err; + *x1 += x1_dot * dt; + *x2 += x2_dot * dt; + } break; + + case FOC_OBSERVER_ORTEGA_ITERATIVE: { + // Iterative with some trial and error + const int iterations = 6; + const float dt_iteration = dt / (float)iterations; + for (int i = 0;i < iterations;i++) { + float err = lambda_2 - (SQ(*x1 - L_ia) + SQ(*x2 - L_ib)); + float gamma_tmp = gamma_half; + if (utils_truncate_number_abs(&err, lambda_2 * 0.2)) { + gamma_tmp *= 10.0; + } + float x1_dot = -R_ia + v_alpha + gamma_tmp * (*x1 - L_ia) * err; + float x2_dot = -R_ib + v_beta + gamma_tmp * (*x2 - L_ib) * err; - // Iterative with some trial and error - const int iterations = 6; - const float dt_iteration = dt / (float)iterations; - for (int i = 0;i < iterations;i++) { - float err = lambda_2 - (SQ(*x1 - L_ia) + SQ(*x2 - L_ib)); - float gamma_tmp = gamma_half; - if (utils_truncate_number_abs(&err, lambda_2 * 0.2)) { - gamma_tmp *= 10.0; - } - float x1_dot = -R_ia + v_alpha + gamma_tmp * (*x1 - L_ia) * err; - float x2_dot = -R_ib + v_beta + gamma_tmp * (*x2 - L_ib) * err; + *x1 += x1_dot * dt_iteration; + *x2 += x2_dot * dt_iteration; + } + } break; - *x1 += x1_dot * dt_iteration; - *x2 += x2_dot * dt_iteration; + default: + break; } - // Same as above, but without iterations. + // Same as iterative, but without iterations. // float err = lambda_2 - (SQ(*x1 - L_ia) + SQ(*x2 - L_ib)); // float gamma_tmp = gamma_half; // if (utils_truncate_number_abs(&err, lambda_2 * 0.2)) { @@ -2401,7 +2425,9 @@ void observer_update(float v_alpha, float v_beta, float i_alpha, float i_beta, UTILS_NAN_ZERO(*x1); UTILS_NAN_ZERO(*x2); - *phase = utils_fast_atan2(*x2 - L_ib, *x1 - L_ia); + if (phase) { + *phase = utils_fast_atan2(*x2 - L_ib, *x1 - L_ia); + } } static void pll_run(float phase, float dt, volatile float *phase_var, @@ -2429,6 +2455,7 @@ static void pll_run(float phase, float dt, volatile float *phase_var, * i_alpha * i_beta * v_bus + * speed_rad_s * * Parameters that will be updated in this function: * i_bus @@ -2479,18 +2506,60 @@ static void control_current(volatile motor_state_t *state_m, float dt) { state_m->vd_int += Ierr_d * (ki * dt); state_m->vq_int += Ierr_q * (ki * dt); - // Saturation - utils_saturate_vector_2d((float*)&state_m->vd, (float*)&state_m->vq, - (2.0 / 3.0) * max_duty * SQRT3_BY_2 * state_m->v_bus); + // Decoupling + float dec_vd = 0.0; + float dec_vq = 0.0; + + if (m_control_mode < CONTROL_MODE_HANDBRAKE && m_conf->foc_cc_decoupling != FOC_CC_DECOUPLING_DISABLED) { + switch (m_conf->foc_cc_decoupling) { + case FOC_CC_DECOUPLING_CROSS: + dec_vd = state_m->iq * state_m->speed_rad_s * m_conf->foc_motor_l; + dec_vq = state_m->id * state_m->speed_rad_s * m_conf->foc_motor_l; + break; + + case FOC_CC_DECOUPLING_BEMF: + dec_vq = state_m->speed_rad_s * m_conf->foc_motor_flux_linkage; + break; + + case FOC_CC_DECOUPLING_CROSS_BEMF: + dec_vd = state_m->iq * state_m->speed_rad_s * m_conf->foc_motor_l; + dec_vq = state_m->id * state_m->speed_rad_s * m_conf->foc_motor_l + state_m->speed_rad_s * m_conf->foc_motor_flux_linkage; + break; + + default: + break; + } + } + + state_m->vd -= dec_vd; + state_m->vq += dec_vq; + float max_v_mag = (2.0 / 3.0) * max_duty * SQRT3_BY_2 * state_m->v_bus; + + // Saturation + utils_saturate_vector_2d((float*)&state_m->vd, (float*)&state_m->vq, max_v_mag); state_m->mod_d = state_m->vd / ((2.0 / 3.0) * state_m->v_bus); state_m->mod_q = state_m->vq / ((2.0 / 3.0) * state_m->v_bus); - // Windup protection -// utils_saturate_vector_2d((float*)&state_m->vd_int, (float*)&state_m->vq_int, -// (2.0 / 3.0) * max_duty * SQRT3_BY_2 * state_m->v_bus); - utils_truncate_number_abs((float*)&state_m->vd_int, (2.0 / 3.0) * max_duty * SQRT3_BY_2 * state_m->v_bus); - utils_truncate_number_abs((float*)&state_m->vq_int, (2.0 / 3.0) * max_duty * SQRT3_BY_2 * state_m->v_bus); + // Integrator windup protection + // This is important, tricky and probably needs improvement. + // Currently we check if the integrator causes over modulation and decrease the components + // that contribute to the over modulation. + float int_over_mod = sqrtf(SQ(state_m->vd_int - dec_vd) + SQ(state_m->vq_int + dec_vq)) - max_v_mag; + float max_int_over_mod = -0.1; + if (int_over_mod > max_int_over_mod) { + float diff_vd = fabsf((state_m->vd_int - dec_vd)) - fabsf(dec_vd); + float diff_vq = fabsf((state_m->vq_int + dec_vq)) - fabsf(dec_vq); + int_over_mod -= max_int_over_mod; + float dec_gain = 0.01; + + if (diff_vd > 0.0) { + state_m->vd_int *= 1.0 - dec_gain * int_over_mod; + } + if (diff_vq > 0.0) { + state_m->vq_int *= 1.0 - dec_gain * int_over_mod; + } + } // TODO: Have a look at this? state_m->i_bus = state_m->mod_d * state_m->id + state_m->mod_q * state_m->iq; @@ -2522,7 +2591,8 @@ static void control_current(volatile motor_state_t *state_m, float dt) { svm(-mod_alpha, -mod_beta, top, &duty1, &duty2, &duty3, (uint32_t*)&state_m->svm_sector); TIMER_UPDATE_DUTY(duty1, duty2, duty3); - if(virtual_motor_is_connected() == false){//do not allow to turn on PWM outputs if virtual motor is used + // do not allow to turn on PWM outputs if virtual motor is used + if(virtual_motor_is_connected() == false) { if (!m_output_on) { start_pwm_hw(); } diff --git a/terminal.c b/terminal.c index 537b7bda9..e778bcfea 100644 --- a/terminal.c +++ b/terminal.c @@ -34,6 +34,8 @@ #include "drv8320s.h" #include "drv8323s.h" #include "app.h" +#include "comm_usb.h" +#include "comm_usb_serial.h" #include <string.h> #include <stdio.h> @@ -448,6 +450,13 @@ void terminal_process_string(char *str) { commands_printf("FOC Current Offsets: %d %d %d", curr0_offset, curr1_offset, curr2_offset); +#ifdef COMM_USE_USB + commands_printf("USB config events: %d", comm_usb_serial_configured_cnt()); + commands_printf("USB write timeouts: %u", comm_usb_get_write_timeout_cnt()); +#else + commands_printf("USB not enabled on hardware."); +#endif + commands_printf(" "); } else if (strcmp(argv[0], "foc_openloop") == 0) { if (argc == 3) { @@ -684,6 +693,8 @@ void terminal_process_string(char *str) { encoder_sincos_get_signal_above_max_error_cnt(), (double)encoder_sincos_get_signal_above_max_error_rate() * (double)100.0); } + } else if (strcmp(argv[0], "uptime") == 0) { + commands_printf("Uptime: %.2f s\n", (double)chVTGetSystemTimeX() / (double)CH_CFG_ST_FREQUENCY); } // The help command @@ -799,6 +810,9 @@ void terminal_process_string(char *str) { commands_printf("encoder"); commands_printf(" Prints the status of the AS5047, AD2S1205, or TS5700N8501 encoder."); + commands_printf("uptime"); + commands_printf(" Prints how many seconds have passed since boot."); + for (int i = 0;i < callback_write;i++) { if (callbacks[i].cbf == 0) { continue; diff --git a/utils.c b/utils.c index 4194f9605..646742461 100644 --- a/utils.c +++ b/utils.c @@ -344,7 +344,7 @@ float utils_fast_atan2(float y, float x) { */ bool utils_saturate_vector_2d(float *x, float *y, float max) { bool retval = false; - float mag = sqrtf(*x * *x + *y * *y); + float mag = sqrtf(SQ(*x) + SQ(*y)); max = fabsf(max); if (mag < 1e-10) { diff --git a/utils.h b/utils.h index f6642437c..98713a73f 100644 --- a/utils.h +++ b/utils.h @@ -77,7 +77,7 @@ uint32_t utils_crc32c(uint8_t *data, uint32_t len); * @param filter_constant * Filter constant. Range 0.0 to 1.0, where 1.0 gives the unfiltered value. */ -#define UTILS_LP_FAST(value, sample, filter_constant) (value -= (filter_constant) * (value - (sample))) +#define UTILS_LP_FAST(value, sample, filter_constant) (value -= (filter_constant) * ((value) - (sample))) // Some constants #define ONE_BY_SQRT3 (0.57735026919)