#include #include #include "8b10b.h" #include "crc32.h" #include "xorshift.h" #include "protocol.h" #include "generated/waveform_tables.h" volatile uint64_t sys_time_us; static uint32_t read_fuse_monitor(void); static void set_rj45_leds(uint32_t leds); static void set_status_leds(uint32_t leds); static void dma_tx_constant(size_t table_size, uint16_t constant); static void dma_tx_waveform(size_t table_size, const uint16_t *table); #define SYNC_INTERVAL 13 static size_t tx_bitpos = 0; static size_t tx_sympos = 0; static int tx_last_bit = 0; static struct state_8b10b_enc encoder_state_8b10b; static uint32_t packet_rng_state; union tx_buf_union { struct data_packet packet; uint8_t bytes[sizeof(struct data_packet)]; }; static union tx_buf_union tx_buf[3]; static union tx_buf_union *tx_buf_read = &tx_buf[0]; static union tx_buf_union *tx_buf_idle = &tx_buf[1]; static union tx_buf_union *tx_buf_write = &tx_buf[2]; static bool idle_buf_ready = false; void update_tx_buf(void); int hex_to_int(char *hex, size_t len); int hex_to_int(char *hex, size_t len) { int rv = 0; while (len--) { rv = rv<<4; char c = hex[len]; if ('0' <= c && c <= '9') c = c - '0'; else if ('a' <= c && c <= 'f') c = c - 'a' + 0xa; else if ('A' <= c && c <= 'F') c = c - 'A' + 0xa; else c = 0; rv |= c; } return rv; } enum leds { LED_ON = 1, LED_PING = 2, LED_OVERHEAT = 4, LED_CONTROL_ERR = 8, LED_INPUT_ERR = 16, LED_OUTPUT_ERR = 32 }; char rxbuf[256]; size_t rxp = 0; int main(void) { /* Configure clocks for 64 MHz system clock. * * HSE @ 8 MHz --[PLL x16 /2]--> PLL "R" clock @ 64 MHz */ /* Enable peripherals */ RCC->APBENR1 |= RCC_APBENR1_PWREN; /* Enable High-speed external crystal oscillator. The board has an 8 MHz crystal. */ RCC->CR |= RCC_CR_HSEON; while (!(RCC->CR & RCC_CR_HSERDY)) { /* wait for HSE osc to stabilize. */ } /* Increase flash wait states to 2 required for operation above 48 MHz */ FLASH->ACR = (FLASH->ACR & ~FLASH_ACR_LATENCY_Msk) | (2<ACR & FLASH_ACR_LATENCY_Msk) != (2<PLLCFGR = (16<CR |= RCC_CR_PLLON; while (!(RCC->CR & RCC_CR_PLLRDY)) { /* wait for PLL to stabilize. */ } /* Switch SYSCLK to PLL source. */ RCC->CFGR |= (2<CFGR & RCC_CFGR_SWS_Msk) != (2<AHBENR |= RCC_AHBENR_DMA1EN; RCC->APBENR1 |= RCC_APBENR1_USART3EN | RCC_APBENR1_I2C1EN; RCC->APBENR2 |= RCC_APBENR2_USART1EN | RCC_APBENR2_TIM1EN; RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN | RCC_IOPENR_GPIOCEN | RCC_IOPENR_GPIODEN; /* GPIOA: * A0: MON_H * A1: MON_FAULT_CURRENT * A2: MON_L * A3: (testpoint) * A4: VIN_MON * A5: (testpoint) * A6: RJ45 LED 2 * A7: Pulse RX * A8: Fuse monitor 6 * A9: RS485 TX * A10: RS485 RX * A11: Fuse monitor 1 * A12: RS485 DE * A13: SWDIO * A14: SWCLK * A15: Fuse monitor 4 */ GPIOA->MODER = ANALOG(0) | ANALOG(1) | ANALOG(2) | ANALOG(4) | IN(3) | IN(5) | OUT(6) | ANALOG(7) | IN(8) | IN(11) | IN(15) | AF(9) | AF(10) | AF(12) | AF(13) | AF(14); GPIOA->AFR[1] = AFRH(9, 1) | AFRH(10, 1) | AFRH(12, 1) | AFRH(13, 0) | AFRH(14, 0); GPIOA->OSPEEDR = (3<<(2*9)) | (3<<(2*12)) | (3<<(2*13)); /* GPIOB: * B0: Driver A low (TIM1_CH2N) * B1: Driver B low (TIM1_CH3N) * B2: RJ45 LED 1 * B3: Driver A high (TIM1_CH2) * B4: V_ISO_SENSE * B5: (testpoint) * B6: SCL * B7: SDA * B8: DBG_TX * B9: DBG_RX * B10: LED 3 "On" * B11: LED 5 "RS458 Ping" * B12: LED 1 "Overheating" * B13: LED 6 "Control Error" * B14: LED 4 "Input Error" * B15: LED 2 "Output Error" */ GPIOB->MODER = AF(0) | AF(1) | AF(3) | OUT(2) | IN(4) | IN(5) | AF(6) | AF(7) | AF(8) | AF(9) | OUT(10) | OUT(11) | OUT(12) | OUT(13) | OUT(14) | OUT(15); GPIOB->AFR[0] = AFRL(0, 2) | AFRL(1, 2) | AFRL(3, 1) | AFRL(6, 6) | AFRL(7, 6); GPIOB->AFR[1] = AFRH(8, 4) | AFRH(9, 4); GPIOB->OSPEEDR = (3<<0) | (3<<1) | (3<<3); /* GPIOC: * C0, C3: (testpoint) * C1: Fan 2 PWM * C2: Fan 1 PWM * C4: RJ45 LED 4 * C5: RJ45 LED 3 * C6: Fuse monitor 7 * C7: Fuse monitor 2 * C8: Fuse monitor 5 * C9: (testpoint) * C10: Driver B high * C11-C15: (testpoint) */ GPIOC->MODER = IN(0) | OUT(1) | OUT(2) | IN(3) | IN(9) | IN(11) | IN(12) | IN(13) | IN(14) | IN(15) | OUT(4) | OUT(5) | IN(6) | IN(7) | IN(8) | AF(10); GPIOC->OTYPER = (1<<1) | (1<<2); GPIOC->AFR[1] = AFRH(10, 2); GPIOC->OSPEEDR = (3<<10); GPIOC->BRR = (1<<1) | (1<<2); /* Turn down fans (most fans don't turn off at 0% PWM) */ /* GPIOD: * D0-D6: (testpoint) * D8: Fuse monitor 3 * D9: Fuse monitor 0 */ GPIOD->MODER = IN(0) | IN(1) | IN(2) | IN(3) | IN(4) | IN(5) | IN(6) | IN(8) | IN(9); for (int i=0; i<10; i++) { set_status_leds(LED_ON); delay_us(250*1000); set_status_leds(0); delay_us(250*1000); } GPIOC->BSRR = (1<<1) | (1<<2); /* Enable fans */ for (int i=0; i<10; i++) { set_status_leds(LED_ON); delay_us(250*1000); set_status_leds(0); delay_us(250*1000); } TIM1->CCMR1 = (6<CCMR2 = (6<CCER = TIM_CCER_CC2E | TIM_CCER_CC2NE | TIM_CCER_CC2NP | TIM_CCER_CC3E | TIM_CCER_CC3NE | TIM_CCER_CC3P; TIM1->BDTR = (8<DCR = (14<PSC = 3; TIM1->ARR = 250; TIM1->CCR2 = 64; TIM1->CCR3 = 192; TIM1->DIER = TIM_DIER_UDE; TIM1->CR1 |= TIM_CR1_CEN; DMAMUX1->CCR = 25; DMA1_Channel1->CPAR = (uint32_t)&TIM1->DMAR; NVIC_EnableIRQ(DMA1_Channel1_IRQn); NVIC_SetPriority(DMA1_Channel1_IRQn, 0); dma_tx_constant(COUNT_OF(waveform_zero_one), 0x00); xfr_8b10b_encode_reset(&encoder_state_8b10b); USART1->CR1 = /* 8-bit -> M1, M0 clear */ /* OVER8 clear. Use default 16x oversampling */ /* CMIF clear */ /* MME clear */ /* WAKE clear */ /* PCE, PS clear */ /* RXNEIE, other interrupts clear */ USART_CR1_TE | USART_CR1_RE; USART1->CR3 |= USART_CR3_DEM; /* Output DE signal on RTS pin */ USART1->BRR = 6667; /* Set baudrate to 9600 Bd */ USART1->CR1 |= USART_CR1_UE; /* And... go! */ int rj45_rx_ctr = 0; int ping_ctr = 0; int control_err_ctr = 0; while (23) { if (rj45_rx_ctr) { set_rj45_leds(0x5); rj45_rx_ctr--; } else { set_rj45_leds(0x0); } int leds = LED_ON; if (ping_ctr) { leds |= LED_PING; ping_ctr--; } if (control_err_ctr) { leds |= LED_CONTROL_ERR; control_err_ctr--; } set_status_leds(leds); int isr = USART1->ISR; if ((isr & USART_ISR_ORE) || (isr & USART_ISR_FE)) { USART1->ICR = USART_ICR_ORECF | USART_ICR_FECF; } if (isr & USART_ISR_RXNE_RXFNE) { rj45_rx_ctr = 20000; char c = USART1->RDR; if (c == '\n') { if (rxp > 2 && rxp != 4*16*3) { control_err_ctr = 1000000; rxp = 0; continue; } for (size_t i=0; i<16; i++) { int brightness = hex_to_int(&rxbuf[DRIVER_ADDR*16*3 + i*3], 1); int channels = hex_to_int(&rxbuf[DRIVER_ADDR*16*3 + i*3 + 1], 2); tx_buf_write->packet.channels[i] = channels; if ((i&1) == 0) { tx_buf_write->packet.brightness[i>>1] = brightness; } else { tx_buf_write->packet.brightness[i>>1] |= brightness<<4; } } rxp = 0; ping_ctr = 500000; update_tx_buf(); } else { if (rxp <= sizeof(rxbuf)) { rxbuf[rxp] = c; rxp ++; } } } } } void dma_tx_waveform(size_t table_size, const uint16_t *table) { DMA1_Channel1->CCR = 0; DMA1_Channel1->CCR = (1<CNDTR = table_size; DMA1_Channel1->CMAR = (uint32_t)table; DMA1_Channel1->CCR |= DMA_CCR_EN; } void dma_tx_constant(size_t table_size, uint16_t constant) { static uint16_t tx_constant[2]; tx_constant[0] = constant; tx_constant[1] = constant; DMA1_Channel1->CCR = 0; DMA1_Channel1->CCR = (1<CNDTR = table_size; DMA1_Channel1->CMAR = (uint32_t)&tx_constant; DMA1_Channel1->CCR |= DMA_CCR_EN; } int8_t bit_arr[4096]; size_t bit_pos = 0; int16_t sym_arr[512]; size_t sym_pos = 0; uint16_t cnd_arr[512]; size_t cnd_pos = 0; void DMA1_Channel1_IRQHandler() { static int transfer_errors = 0; static int current_symbol = 0; if (DMA1->ISR & DMA_ISR_TEIF1) { transfer_errors ++; } DMA1->IFCR = DMA_IFCR_CGIF1; int bit = !!(current_symbol & (1<bytes[tx_sympos]; packet_rng_state = xorshift32(packet_rng_state); b ^= packet_rng_state; current_symbol = xfr_8b10b_encode(&encoder_state_8b10b, b); sym_arr[sym_pos] = current_symbol; tx_sympos ++; } sym_pos++; if (sym_pos == COUNT_OF(sym_arr)) { sym_pos = 0; } } else { tx_bitpos --; } } void update_tx_buf() { uint32_t crc = crc32_reset(); for (size_t i=0; ibytes[i]); } tx_buf_write->packet.crc = crc32_finalize(crc); __disable_irq(); union tx_buf_union *tmp = tx_buf_idle; tx_buf_idle = tx_buf_write; tx_buf_write = tmp; idle_buf_ready = true; __enable_irq(); } uint32_t read_fuse_monitor() { uint32_t idr_a = GPIOA->IDR; uint32_t idr_c = GPIOC->IDR; uint32_t idr_d = GPIOD->IDR; int fm0 = !!(idr_d & (1<<9)); int fm1 = !!(idr_a & (1<<11)); int fm2 = !!(idr_c & (1<<7)); int fm3 = !!(idr_d & (1<<8)); int fm4 = !!(idr_a & (1<<15)); int fm5 = !!(idr_c & (1<<8)); int fm6 = !!(idr_a & (1<<8)); int fm7 = !!(idr_c & (1<<6)); return (fm0<<0) | (fm1<<1) | (fm2<<2) | (fm3<<3) | (fm4<<4) | (fm5<<5) | (fm6<<6) | (fm7<<7); } void set_rj45_leds(uint32_t leds) { leds = ~leds; if (leds&1) { GPIOB->BSRR = (1<<2); } else { GPIOB->BSRR = (1<<2)<<16; } if (leds&2) { GPIOA->BSRR = (1<<6); } else { GPIOA->BSRR = (1<<6)<<16; } if (leds&4) { GPIOC->BSRR = (1<<5); } else { GPIOC->BSRR = (1<<5)<<16; } if (leds&8) { GPIOC->BSRR = (1<<4); } else { GPIOC->BSRR = (1<<4)<<16; } } void set_status_leds(uint32_t leds) { GPIOB->BSRR = ((0x3f<<10)<<16) | (((~leds)&0x3f)<<10); } void SysTick_Handler() { sys_time_us += SYSTICK_INTERVAL_US; } void HardFault_Handler() { asm volatile ("bkpt"); } void delay_us(int duration_us) { while (duration_us--) { for (int i=0; i<3; i++) { asm volatile ("nop"); } } } void *memcpy(void *restrict dest, const void *restrict src, size_t n) { unsigned char *d = dest; const unsigned char *s = src; for (; n; n--) { *d++ = *s++; } return dest; } void *memmove(void *dest, const void *src, size_t n) { return memcpy(dest, src, n); } void *memset(void *dest, int c, size_t n) { unsigned char *d = dest; while (n--) { *d++ = c; } return dest; } size_t strlen(const char *s) { const char *start = s; while (*s) { s++; } return s - start; } void __libc_init_array (void) __attribute__((weak)); void __libc_init_array () { }