#include #include "app_config.h" #include #include #include #include #include #include "chip.h" #include "stm32.h" #include #include "nvic.h" #include "bl_macros.h" #include "driver.h" #include "crc.h" #include "timer.h" #include #define INAK_TIMEOUT 65535 #define CAN_1MBAUD_SJW 0 #define CAN_1MBAUD_BS1 6u #define CAN_1MBAUD_BS2 0 #define CAN_1MBAUD_PRESCALER 4u #define CAN_500KBAUD_SJW 0 #define CAN_500KBAUD_BS1 6u #define CAN_500KBAUD_BS2 0 #define CAN_500KBAUD_PRESCALER 8u #define CAN_250KBAUD_SJW 0 #define CAN_250KBAUD_BS1 6u #define CAN_250KBAUD_BS2 0 #define CAN_250KBAUD_PRESCALER 16u #define CAN_125KBAUD_SJW 0 #define CAN_125KBAUD_BS1 6u #define CAN_125KBAUD_BS2 0 #define CAN_125KBAUD_PRESCALER 32u #define CAN_BTR_LBK_SHIFT 30 #define WAIT_TX_READY_MS ((TIMER_HRT_CYCLES_PER_MS-(TIMER_HRT_CYCLES_PER_MS/4)) /* Number of CPU cycles for a single bit time at the supported speeds */ #define CAN_1MBAUD_BIT_CYCLES (1*(TIMER_HRT_CYCLES_PER_US)) #define CAN_500KBAUD_BIT_CYCLES (2*(TIMER_HRT_CYCLES_PER_US)) #define CAN_250KBAUD_BIT_CYCLES (4*(TIMER_HRT_CYCLES_PER_US)) #define CAN_125KBAUD_BIT_CYCLES (8*(TIMER_HRT_CYCLES_PER_US)) /* All the mesured samples were off byt 28 counts this implys that * the CAN_MSR_RX is sampled on a differnt clock then the CPU */ #define CAN_BAUD_ADJUST 28 #define CAN_BAUD_TIME_IN_MS 200 #define CAN_BAUD_SAMPLES_NEEDED 32 #define CAN_BAUD_SAMPLES_DISCARDED 8 int can_init(can_speed_t speed, uint8_t mode) { int speedndx = speed -1; /* * TODO: use full-word writes to reduce the number of loads/stores. * * Also consider filter use -- maybe set filters for all the message types we * want. */ const uint32_t bitrates[] = { (CAN_125KBAUD_SJW << 24) | (CAN_125KBAUD_BS1 << 16) | (CAN_125KBAUD_BS2 << 20) | (CAN_125KBAUD_PRESCALER - 1), (CAN_250KBAUD_SJW << 24) | (CAN_250KBAUD_BS1 << 16) | (CAN_250KBAUD_BS2 << 20) | (CAN_250KBAUD_PRESCALER - 1), (CAN_500KBAUD_SJW << 24) | (CAN_500KBAUD_BS1 << 16) | (CAN_500KBAUD_BS2 << 20) | (CAN_500KBAUD_PRESCALER - 1), (CAN_1MBAUD_SJW << 24) | (CAN_1MBAUD_BS1 << 16) | (CAN_1MBAUD_BS2 << 20) | (CAN_1MBAUD_PRESCALER - 1) }; /* Remove Unknow Offset */ if (speedndx < 0 || speedndx > (int)arraySize(bitrates)) { return -EINVAL; } uint32_t timeout; /* * Reset state is 0x0001 0002 CAN_MCR_DBF|CAN_MCR_SLEEP * knock down Sleep and raise CAN_MCR_INRQ */ putreg32(CAN_MCR_DBF | CAN_MCR_INRQ, STM32_CAN1_MCR); /* Wait until initialization mode is acknowledged */ for (timeout = INAK_TIMEOUT; timeout > 0; timeout--) { if ((getreg32(STM32_CAN1_MSR) & CAN_MSR_INAK) != 0) { /* We are in initialization mode */ break; } } if (timeout < 1) { /* * Initialization failed, not much we can do now other than try a normal * startup. */ return -ETIME; } putreg32(bitrates[speedndx]| mode << CAN_BTR_LBK_SHIFT, STM32_CAN1_BTR); putreg32(CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_DBF, STM32_CAN1_MCR); for (timeout = INAK_TIMEOUT; timeout > 0; timeout--) { if ((getreg32(STM32_CAN1_MSR) & CAN_MSR_INAK) == 0) { /* We are in initialization mode */ break; } } if (timeout < 1) { return -ETIME; } /* * CAN filter initialization -- accept everything on RX FIFO 0, and only * GetNodeInfo requests on RX FIFO 1. */ putreg32(CAN_FMR_FINIT, STM32_CAN1_FMR); putreg32(0, STM32_CAN1_FA1R); /* Disable all filters */ putreg32(3, STM32_CAN1_FS1R); /* Enable 32-bit mode for filters 0 and 1 */ /* Filter 0 masks -- data type ID 551 only */ putreg32(UAVCAN_GETNODEINFO_DTID << 22, STM32_CAN1_FIR(0, 1)); /* Top 10 bits of ID */ putreg32(0xFFC00000, STM32_CAN1_FIR(0, 2)); /* Filter 1 masks -- everything is don't-care */ putreg32(0, STM32_CAN1_FIR(1, 1)); putreg32(0, STM32_CAN1_FIR(1, 2)); putreg32(0, STM32_CAN1_FM1R); /* Mask mode for all filters */ putreg32(1, STM32_CAN1_FFA1R); /* FIFO 1 for filter 0, FIFO 0 for the * rest of filters */ putreg32(3, STM32_CAN1_FA1R); /* Enable filters 0 and 1 */ putreg32(0, STM32_CAN1_FMR); /* Leave init Mode */ return OK; } void can_tx(uint32_t message_id, size_t length, const uint8_t * message, uint8_t mailbox) { uint32_t data[2]; memcpy(data, message, sizeof(data)); /* * Just block while waiting for the mailbox. Give it an extra 0.75 ms per * frame to avoid an issue Ben was seeing with packets going missing on a USBtin. */ uint32_t mask = CAN_TSR_TME0 << mailbox; time_hrt_cycles_t begin = timer_hrt_read(); while (((getreg32(STM32_CAN1_TSR) & mask) == 0) || timer_hrt_elapsed(begin, timer_hrt_read()) < WAIT_TX_READY_MS)); putreg32(length & CAN_TDTR_DLC_MASK, STM32_CAN1_TDTR(mailbox)); putreg32(data[0], STM32_CAN1_TDLR(mailbox)); putreg32(data[1], STM32_CAN1_TDHR(mailbox)); putreg32((message_id << CAN_TIR_EXID_SHIFT) | CAN_TIR_IDE | CAN_TIR_TXRQ, STM32_CAN1_TIR(mailbox)); } uint8_t can_rx(uint32_t * out_message_id, size_t * out_length, uint8_t * out_message, uint8_t fifo) { uint32_t data[2]; uint8_t rv = 0; const uint32_t fifos[] = { STM32_CAN1_RF0R, STM32_CAN1_RF1R }; if (getreg32(fifos[fifo & 1]) & CAN_RFR_FMP_MASK) { rv = 1; /* If so, process it */ *out_message_id = getreg32(STM32_CAN1_RIR(fifo) & CAN_RIR_EXID_MASK) >> CAN_RIR_EXID_SHIFT; *out_length = getreg32(STM32_CAN1_RDTR(fifo) & CAN_RDTR_DLC_MASK) >> CAN_RDTR_DLC_SHIFT; data[0] = getreg32(STM32_CAN1_RDLR(fifo)); data[1] = getreg32(STM32_CAN1_RDHR(fifo)); putreg32(CAN_RFR_RFOM, fifos[fifo & 1]); memcpy(out_message, data, sizeof(data)); } return rv; } static inline uint32_t read_msr_rx(void) { return getreg32(STM32_CAN1_MSR) & CAN_MSR_RX; } static uint32_t read_msr(time_hrt_cycles_t *now) { __asm__ __volatile__ ("\tcpsid i\n"); *now = timer_hrt_read(); uint32_t msr = read_msr_rx(); __asm__ __volatile__ ("\tcpsie i\n"); return msr; } static int read_bits_times(time_hrt_cycles_t *times, size_t max) { uint32_t samplecnt = 0; bl_timer_id ab_timer= timer_allocate(modeTimeout|modeStarted, CAN_BAUD_TIME_IN_MS, 0); time_ref_t ab_ref = timer_ref(ab_timer); uint32_t msr; uint32_t last_msr = read_msr(times); while(samplecnt < max && !timer_ref_expired(ab_ref)) { do { msr = read_msr(×[samplecnt]); } while(!(msr ^ last_msr) && !timer_ref_expired(ab_ref)); last_msr = msr; samplecnt++; } timer_free(ab_timer); return samplecnt; } int can_autobaud(can_speed_t *can_speed, bl_timer_id tboot) { *can_speed = CAN_UNKNOWN; volatile int attempt = 0; /* Threshold are at 1.5 Bit times */ /* * We are here because there was a reset or the app invoked * the bootloader with no bit rate set. */ time_hrt_cycles_t bit_time; time_hrt_cycles_t min_cycles; int sample; can_speed_t speed = CAN_125KBAUD; time_hrt_cycles_t samples[128]; while(1) { while(1) { min_cycles = ULONG_MAX; int samplecnt = read_bits_times(samples, arraySize(samples)); if (timer_expired(tboot)) { return CAN_BOOT_TIMEOUT; } if ((getreg32(STM32_CAN1_RF0R) | getreg32(STM32_CAN1_RF1R)) & CAN_RFR_FMP_MASK) { *can_speed = speed; return CAN_OK; } if (samplecnt < CAN_BAUD_SAMPLES_NEEDED ) { continue; } for (sample = 0; sample < samplecnt; sample += 2) { bit_time = samples[sample] = timer_hrt_elapsed(samples[sample], samples[sample+1]); if (sample > CAN_BAUD_SAMPLES_DISCARDED && bit_time < min_cycles) { min_cycles = bit_time; } } break; } uint32_t bit34 = CAN_125KBAUD_BIT_CYCLES - CAN_125KBAUD_BIT_CYCLES/4; samples[1] = min_cycles; speed = CAN_125KBAUD; while(min_cycles < bit34 && speed < CAN_1MBAUD) { speed++; bit34 /= 2; } attempt++; can_init(speed, CAN_Mode_Silent); } /* while(1) */ return CAN_OK; } int can_speed2freq(can_speed_t speed) { return 1000000 >> (CAN_1MBAUD-speed); } can_speed_t can_freq2speed(int freq) { return (freq == 1000000u ? CAN_1MBAUD : freq == 500000u ? CAN_500KBAUD : freq == 250000u ? CAN_250KBAUD : CAN_125KBAUD); }