#include "../config.h" #include "drivers/llcan.h" #include "drivers/llgpio.h" #include "drivers/clock.h" #include "drivers/adc.h" #include "drivers/dac.h" #include "drivers/timer.h" #include "gpio.h" #include "libc.h" #define CAN CAN1 //#define PEDAL_USB #ifdef PEDAL_USB #include "drivers/uart.h" #include "drivers/usb.h" #else // no serial either void puts(const char *a) { UNUSED(a); } void puth(unsigned int i) { UNUSED(i); } #endif #define ENTER_BOOTLOADER_MAGIC 0xdeadbeef uint32_t enter_bootloader_mode; // cppcheck-suppress unusedFunction ; used in headers not included in cppcheck void __initialize_hardware_early(void) { early(); } // ********************* serial debugging ********************* #ifdef PEDAL_USB void debug_ring_callback(uart_ring *ring) { char rcv; while (getc(ring, &rcv) != 0) { (void)putc(ring, rcv); } } int usb_cb_ep1_in(uint8_t *usbdata, int len, bool hardwired) { UNUSED(usbdata); UNUSED(len); UNUSED(hardwired); return 0; } void usb_cb_ep2_out(uint8_t *usbdata, int len, bool hardwired) { UNUSED(usbdata); UNUSED(len); UNUSED(hardwired); } void usb_cb_ep3_out(uint8_t *usbdata, int len, bool hardwired) { UNUSED(usbdata); UNUSED(len); UNUSED(hardwired); } void usb_cb_enumeration_complete(void) {} int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) { UNUSED(hardwired); unsigned int resp_len = 0; uart_ring *ur = NULL; switch (setup->b.bRequest) { // **** 0xe0: uart read case 0xe0: ur = get_ring_by_number(setup->b.wValue.w); if (!ur) { break; } if (ur == &esp_ring) { uart_dma_drain(); } // read while ((resp_len < MIN(setup->b.wLength.w, MAX_RESP_LEN)) && getc(ur, (char*)&resp[resp_len])) { ++resp_len; } break; default: puts("NO HANDLER "); puth(setup->b.bRequest); puts("\n"); break; } return resp_len; } #endif // ***************************** pedal can checksum ***************************** uint8_t pedal_checksum(uint8_t *dat, int len) { uint8_t crc = 0xFF; uint8_t poly = 0xD5; // standard crc8 int i, j; for (i = len - 1; i >= 0; i--) { crc ^= dat[i]; for (j = 0; j < 8; j++) { if ((crc & 0x80U) != 0U) { crc = (uint8_t)((crc << 1) ^ poly); } else { crc <<= 1; } } } return crc; } // ***************************** can port ***************************** // addresses to be used on CAN #define CAN_GAS_INPUT 0x200 #define CAN_GAS_OUTPUT 0x201U #define CAN_GAS_SIZE 6 #define COUNTER_CYCLE 0xFU // cppcheck-suppress unusedFunction ; used in headers not included in cppcheck void CAN1_TX_IRQHandler(void) { // clear interrupt CAN->TSR |= CAN_TSR_RQCP0; } // two independent values uint16_t gas_set_0 = 0; uint16_t gas_set_1 = 0; #define MAX_TIMEOUT 10U uint32_t timeout = 0; uint32_t current_index = 0; #define NO_FAULT 0U #define FAULT_BAD_CHECKSUM 1U #define FAULT_SEND 2U #define FAULT_SCE 3U #define FAULT_STARTUP 4U #define FAULT_TIMEOUT 5U #define FAULT_INVALID 6U uint8_t state = FAULT_STARTUP; // cppcheck-suppress unusedFunction ; used in headers not included in cppcheck void CAN1_RX0_IRQHandler(void) { while ((CAN->RF0R & CAN_RF0R_FMP0) != 0) { #ifdef DEBUG puts("CAN RX\n"); #endif int address = CAN->sFIFOMailBox[0].RIR >> 21; if (address == CAN_GAS_INPUT) { // softloader entry if (GET_BYTES_04(&CAN->sFIFOMailBox[0]) == 0xdeadface) { if (GET_BYTES_48(&CAN->sFIFOMailBox[0]) == 0x0ab00b1e) { enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; NVIC_SystemReset(); } else if (GET_BYTES_48(&CAN->sFIFOMailBox[0]) == 0x02b00b1e) { enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; NVIC_SystemReset(); } else { puts("Failed entering Softloader or Bootloader\n"); } } // normal packet uint8_t dat[8]; for (int i=0; i<8; i++) { dat[i] = GET_BYTE(&CAN->sFIFOMailBox[0], i); } uint16_t value_0 = (dat[0] << 8) | dat[1]; uint16_t value_1 = (dat[2] << 8) | dat[3]; bool enable = ((dat[4] >> 7) & 1U) != 0U; uint8_t index = dat[4] & COUNTER_CYCLE; if (pedal_checksum(dat, CAN_GAS_SIZE - 1) == dat[5]) { if (((current_index + 1U) & COUNTER_CYCLE) == index) { #ifdef DEBUG puts("setting gas "); puth(value); puts("\n"); #endif if (enable) { gas_set_0 = value_0; gas_set_1 = value_1; } else { // clear the fault state if values are 0 if ((value_0 == 0U) && (value_1 == 0U)) { state = NO_FAULT; } else { state = FAULT_INVALID; } gas_set_0 = 0; gas_set_1 = 0; } // clear the timeout timeout = 0; } current_index = index; } else { // wrong checksum = fault state = FAULT_BAD_CHECKSUM; } } // next CAN->RF0R |= CAN_RF0R_RFOM0; } } // cppcheck-suppress unusedFunction ; used in headers not included in cppcheck void CAN1_SCE_IRQHandler(void) { state = FAULT_SCE; llcan_clear_send(CAN); } uint32_t pdl0 = 0; uint32_t pdl1 = 0; unsigned int pkt_idx = 0; int led_value = 0; // cppcheck-suppress unusedFunction ; used in headers not included in cppcheck void TIM3_IRQHandler(void) { #ifdef DEBUG puth(TIM3->CNT); puts(" "); puth(pdl0); puts(" "); puth(pdl1); puts("\n"); #endif // check timer for sending the user pedal and clearing the CAN if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) { uint8_t dat[8]; dat[0] = (pdl0 >> 8) & 0xFFU; dat[1] = (pdl0 >> 0) & 0xFFU; dat[2] = (pdl1 >> 8) & 0xFFU; dat[3] = (pdl1 >> 0) & 0xFFU; dat[4] = ((state & 0xFU) << 4) | pkt_idx; dat[5] = pedal_checksum(dat, CAN_GAS_SIZE - 1); CAN->sTxMailBox[0].TDLR = dat[0] | (dat[1] << 8) | (dat[2] << 16) | (dat[3] << 24); CAN->sTxMailBox[0].TDHR = dat[4] | (dat[5] << 8); CAN->sTxMailBox[0].TDTR = 6; // len of packet is 5 CAN->sTxMailBox[0].TIR = (CAN_GAS_OUTPUT << 21) | 1U; ++pkt_idx; pkt_idx &= COUNTER_CYCLE; } else { // old can packet hasn't sent! state = FAULT_SEND; #ifdef DEBUG puts("CAN MISS\n"); #endif } // blink the LED set_led(LED_GREEN, led_value); led_value = !led_value; TIM3->SR = 0; // up timeout for gas set if (timeout == MAX_TIMEOUT) { state = FAULT_TIMEOUT; } else { timeout += 1U; } } // ***************************** main code ***************************** void pedal(void) { // read/write pdl0 = adc_get(ADCCHAN_ACCEL0); pdl1 = adc_get(ADCCHAN_ACCEL1); // write the pedal to the DAC if (state == NO_FAULT) { dac_set(0, MAX(gas_set_0, pdl0)); dac_set(1, MAX(gas_set_1, pdl1)); } else { dac_set(0, pdl0); dac_set(1, pdl1); } watchdog_feed(); } int main(void) { __disable_irq(); // init devices clock_init(); periph_init(); gpio_init(); #ifdef PEDAL_USB // enable USB usb_init(); #endif // pedal stuff dac_init(); adc_init(); // init can bool llcan_speed_set = llcan_set_speed(CAN1, 5000, false, false); if (!llcan_speed_set) { puts("Failed to set llcan speed"); } llcan_init(CAN1); // 48mhz / 65536 ~= 732 timer_init(TIM3, 15); NVIC_EnableIRQ(TIM3_IRQn); watchdog_init(); puts("**** INTERRUPTS ON ****\n"); __enable_irq(); // main pedal loop while (1) { pedal(); } return 0; }