k-line 5 baud init (#565)
* k-line slow init * k-line slow init LED bit blink * fix misra violations * better names for k-line methods * debug prints match names * switch to timer * use TIM4 until I figure out TIM5 * tickle faster * fix bit bug and add stop bit * TIM5 working * USB return after addr sent * fix l-line reset * fix misra violations * blink for the ones instead of the zeros * k-line 5 baud fault type * lin check * use TIM5 or wakeup * better namesmaster
parent
2fab502cad
commit
390b8bce81
|
@ -60,7 +60,7 @@ void peripherals_init(void){
|
|||
RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // main counter
|
||||
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // pedal and fan PWM
|
||||
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // gmlan_alt and IR PWM
|
||||
//RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
|
||||
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; // k-line init
|
||||
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // interrupt timer
|
||||
RCC->APB1ENR |= RCC_APB1ENR_PWREN; // for RTC config
|
||||
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
void TIM5_IRQ_Handler(void);
|
||||
|
||||
void setup_timer5(void) {
|
||||
// register interrupt
|
||||
REGISTER_INTERRUPT(TIM5_IRQn, TIM5_IRQ_Handler, 1050000U, FAULT_INTERRUPT_RATE_KLINE_INIT)
|
||||
|
||||
// setup
|
||||
register_set(&(TIM5->PSC), (48-1), 0xFFFFU); // Tick on 1 us
|
||||
register_set(&(TIM5->CR1), TIM_CR1_CEN, 0x3FU); // Enable
|
||||
register_set(&(TIM5->ARR), (5000-1), 0xFFFFFFFFU); // Reset every 5 ms
|
||||
|
||||
// in case it's disabled
|
||||
NVIC_EnableIRQ(TIM5_IRQn);
|
||||
|
||||
// run the interrupt
|
||||
register_set(&(TIM5->DIER), TIM_DIER_UIE, 0x5F5FU); // Update interrupt
|
||||
TIM5->SR = 0;
|
||||
}
|
||||
|
||||
bool k_init = false;
|
||||
bool l_init = false;
|
||||
void setup_kline(bool bitbang) {
|
||||
if (bitbang) {
|
||||
if (k_init) {
|
||||
set_gpio_output(GPIOC, 12, true);
|
||||
}
|
||||
if (l_init) {
|
||||
set_gpio_output(GPIOC, 10, true);
|
||||
}
|
||||
} else {
|
||||
if (k_init) {
|
||||
set_gpio_mode(GPIOC, 12, MODE_ALTERNATE);
|
||||
}
|
||||
if (l_init) {
|
||||
set_gpio_mode(GPIOC, 10, MODE_ALTERNATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void set_bitbanged_kline(bool marking) {
|
||||
// tickle needs to be super fast (so logic level doesn't change)
|
||||
ENTER_CRITICAL();
|
||||
if (k_init) {
|
||||
register_set_bits(&(GPIOC->ODR), (1U << 12));
|
||||
if (!marking) {
|
||||
register_clear_bits(&(GPIOC->ODR), (1U << 12));
|
||||
}
|
||||
}
|
||||
if (l_init) {
|
||||
register_set_bits(&(GPIOC->ODR), (1U << 10));
|
||||
if (!marking) {
|
||||
register_clear_bits(&(GPIOC->ODR), (1U << 10));
|
||||
}
|
||||
}
|
||||
EXIT_CRITICAL();
|
||||
// blink blue LED each time line is pulled low
|
||||
current_board->set_led(LED_BLUE, marking);
|
||||
}
|
||||
|
||||
uint16_t kline_data = 0;
|
||||
uint16_t kline_data_len = 0;
|
||||
uint16_t kline_bit_count = 0;
|
||||
uint16_t kline_tick_count = 0;
|
||||
uint16_t kline_ticks_per_bit = 0;
|
||||
|
||||
void TIM5_IRQ_Handler(void) {
|
||||
if ((TIM5->SR & TIM_SR_UIF) && (kline_data != 0U)) {
|
||||
if (kline_bit_count < kline_data_len) {
|
||||
bool marking = (kline_data & (1U << kline_bit_count)) != 0U;
|
||||
set_bitbanged_kline(marking);
|
||||
} else {
|
||||
register_clear_bits(&(TIM5->DIER), TIM_DIER_UIE); // No update interrupt
|
||||
register_set(&(TIM5->CR1), 0U, 0x3FU); // Disable timer
|
||||
setup_kline(false);
|
||||
kline_data = 0U;
|
||||
USB_WritePacket(NULL, 0, 0); // required call (so send nothing)
|
||||
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
|
||||
}
|
||||
kline_tick_count++;
|
||||
if ((kline_tick_count % kline_ticks_per_bit) == 0U) {
|
||||
kline_bit_count++;
|
||||
}
|
||||
}
|
||||
TIM5->SR = 0;
|
||||
}
|
||||
|
||||
bool bitbang_five_baud_addr(bool k, bool l, uint8_t addr) {
|
||||
bool result = false;
|
||||
if (kline_data == 0U) {
|
||||
k_init = k;
|
||||
l_init = l;
|
||||
kline_data = (addr << 1) + 0x200U; // add start/stop bits
|
||||
kline_data_len = 10U;
|
||||
kline_bit_count = 0;
|
||||
kline_tick_count = 0;
|
||||
kline_ticks_per_bit = 40U; // 200ms == 5bps
|
||||
setup_kline(true);
|
||||
setup_timer5();
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool bitbang_wakeup(bool k, bool l) {
|
||||
bool result = false;
|
||||
if (kline_data == 0U) {
|
||||
k_init = k;
|
||||
l_init = l;
|
||||
kline_data = 2U; // low then high
|
||||
kline_data_len = 2U;
|
||||
kline_bit_count = 0;
|
||||
kline_tick_count = 0;
|
||||
kline_ticks_per_bit = 5U; // 25ms == 40bps
|
||||
setup_kline(true);
|
||||
setup_timer5();
|
||||
result = true;
|
||||
}
|
||||
return result;
|
||||
}
|
|
@ -662,8 +662,11 @@ void usb_setup(void) {
|
|||
break;
|
||||
default:
|
||||
resp_len = usb_cb_control_msg(&setup, resp, 1);
|
||||
USB_WritePacket(resp, MIN(resp_len, setup.b.wLength.w), 0);
|
||||
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
|
||||
// response pending if -1 was returned
|
||||
if (resp_len != -1) {
|
||||
USB_WritePacket(resp, MIN(resp_len, setup.b.wLength.w), 0);
|
||||
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#define FAULT_INTERRUPT_RATE_TIM1 (1U << 16)
|
||||
#define FAULT_INTERRUPT_RATE_TIM3 (1U << 17)
|
||||
#define FAULT_REGISTER_DIVERGENT (1U << 18)
|
||||
#define FAULT_INTERRUPT_RATE_KLINE_INIT (1U << 19)
|
||||
|
||||
// Permanent faults
|
||||
#define PERMANENT_FAULTS 0U
|
||||
|
|
56
board/main.c
56
board/main.c
|
@ -25,6 +25,7 @@
|
|||
#include "drivers/uart.h"
|
||||
#include "drivers/usb.h"
|
||||
#include "drivers/gmlan_alt.h"
|
||||
#include "drivers/kline_init.h"
|
||||
#include "drivers/timer.h"
|
||||
#include "drivers/clock.h"
|
||||
|
||||
|
@ -249,11 +250,7 @@ void usb_cb_enumeration_complete() {
|
|||
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) {
|
||||
unsigned int resp_len = 0;
|
||||
uart_ring *ur = NULL;
|
||||
uint32_t ts;
|
||||
uint32_t ts_timer;
|
||||
timestamp_t t;
|
||||
bool k_wakeup;
|
||||
bool l_wakeup;
|
||||
switch (setup->b.bRequest) {
|
||||
// **** 0xa0: get rtc time
|
||||
case 0xa0:
|
||||
|
@ -562,43 +559,13 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired)
|
|||
break;
|
||||
// **** 0xf0: k-line/l-line wake-up pulse for KWP2000 fast initialization
|
||||
case 0xf0:
|
||||
k_wakeup = (setup->b.wValue.w == 0U) || (setup->b.wValue.w == 2U);
|
||||
l_wakeup = (setup->b.wValue.w == 1U) || (setup->b.wValue.w == 2U);
|
||||
|
||||
ts = TIM2->CNT;
|
||||
ts_timer = ts;
|
||||
if (k_wakeup) {
|
||||
set_gpio_output(GPIOC, 12, false);
|
||||
}
|
||||
if (l_wakeup) {
|
||||
set_gpio_output(GPIOC, 10, false);
|
||||
}
|
||||
|
||||
// hold low for 25 ms
|
||||
while (get_ts_elapsed(TIM2->CNT, ts) < 25000U) {
|
||||
// toggle pin every 5 ms to reset TXD dominant time-out timer
|
||||
if (get_ts_elapsed(TIM2->CNT, ts_timer) >= 5000U) {
|
||||
ts_timer = TIM2->CNT;
|
||||
if (k_wakeup) {
|
||||
register_set_bits(&(GPIOC->ODR), (1U << 12));
|
||||
register_clear_bits(&(GPIOC->ODR), (1U << 12));
|
||||
}
|
||||
if (l_wakeup) {
|
||||
register_set_bits(&(GPIOC->ODR), (1U << 10));
|
||||
register_clear_bits(&(GPIOC->ODR), (1U << 10));
|
||||
}
|
||||
if(board_has_lin()) {
|
||||
bool k = (setup->b.wValue.w == 0U) || (setup->b.wValue.w == 2U);
|
||||
bool l = (setup->b.wValue.w == 1U) || (setup->b.wValue.w == 2U);
|
||||
if (bitbang_wakeup(k, l)) {
|
||||
resp_len = -1; // do not clear NAK yet (wait for bit banging to finish)
|
||||
}
|
||||
}
|
||||
|
||||
if (k_wakeup) {
|
||||
set_gpio_mode(GPIOC, 12, MODE_ALTERNATE);
|
||||
}
|
||||
if (l_wakeup) {
|
||||
set_gpio_mode(GPIOC, 10, MODE_ALTERNATE);
|
||||
}
|
||||
// hold high until 49ms have passed
|
||||
// (start communication needs to follow 49ms to 51ms after start of wakeup)
|
||||
while (get_ts_elapsed(TIM2->CNT, ts) < 49000U) {}
|
||||
break;
|
||||
// **** 0xf1: Clear CAN ring buffer.
|
||||
case 0xf1:
|
||||
|
@ -628,6 +595,17 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired)
|
|||
heartbeat_counter = 0U;
|
||||
break;
|
||||
}
|
||||
// **** 0xf4: k-line/l-line 5 baud initialization
|
||||
case 0xf4:
|
||||
if(board_has_lin()) {
|
||||
bool k = (setup->b.wValue.w == 0U) || (setup->b.wValue.w == 2U);
|
||||
bool l = (setup->b.wValue.w == 1U) || (setup->b.wValue.w == 2U);
|
||||
uint8_t five_baud_addr = (setup->b.wIndex.w & 0xFFU);
|
||||
if (bitbang_five_baud_addr(k, l, five_baud_addr)) {
|
||||
resp_len = -1; // do not clear NAK yet (wait for bit banging to finish)
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
puts("NO HANDLER ");
|
||||
puth(setup->b.bRequest);
|
||||
|
|
|
@ -579,6 +579,14 @@ class Panda(object):
|
|||
if DEBUG:
|
||||
print("kline wakeup done")
|
||||
|
||||
def kline_5baud(self, addr, k=True, l=True):
|
||||
assert k or l, "must specify k-line, l-line, or both"
|
||||
if DEBUG:
|
||||
print("kline 5 baud...")
|
||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf4, 2 if k and l else int(l), addr, b'')
|
||||
if DEBUG:
|
||||
print("kline 5 baud done")
|
||||
|
||||
def kline_drain(self, bus=2):
|
||||
# drain buffer
|
||||
bret = bytearray()
|
||||
|
|
Loading…
Reference in New Issue