465 lines
12 KiB
C
465 lines
12 KiB
C
|
|
#include <global.h>
|
|
#include <string.h>
|
|
#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 time_to_sync = 0;
|
|
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);
|
|
|
|
char usartbuf[256];
|
|
int usartp = 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<<FLASH_ACR_LATENCY_Pos);
|
|
while ((FLASH->ACR & FLASH_ACR_LATENCY_Msk) != (2<<FLASH_ACR_LATENCY_Pos)) {
|
|
/* wait for flash controller to acknowledge change. */
|
|
}
|
|
/* Configure PLL with multiplier 16, divisor 2 for "R" output, and enable "R" (sysclk) output */
|
|
RCC->PLLCFGR = (16<<RCC_PLLCFGR_PLLN_Pos) | (3<<RCC_PLLCFGR_PLLSRC_Pos) | (1<<RCC_PLLCFGR_PLLR_Pos) | RCC_PLLCFGR_PLLREN;
|
|
RCC->CR |= RCC_CR_PLLON;
|
|
while (!(RCC->CR & RCC_CR_PLLRDY)) {
|
|
/* wait for PLL to stabilize. */
|
|
}
|
|
/* Switch SYSCLK to PLL source. */
|
|
RCC->CFGR |= (2<<RCC_CFGR_SW_Pos);
|
|
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != (2<<RCC_CFGR_SWS_Pos)) {
|
|
/* wait for RCC to switch over. */
|
|
}
|
|
|
|
RCC->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)
|
|
* 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) | IN(1) | IN(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->AFR[1] = AFRH(10, 2);
|
|
GPIOC->OSPEEDR = (3<<10);
|
|
|
|
/* 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);
|
|
|
|
delay_us(5*1000*1000);
|
|
|
|
TIM1->CCMR1 = (6<<TIM_CCMR1_OC2M_Pos) | TIM_CCMR1_OC2PE;
|
|
TIM1->CCMR2 = (6<<TIM_CCMR2_OC3M_Pos) | TIM_CCMR2_OC3PE;
|
|
TIM1->CCER = TIM_CCER_CC2E | TIM_CCER_CC2NE | TIM_CCER_CC2NP | TIM_CCER_CC3E | TIM_CCER_CC3NE | TIM_CCER_CC3P;
|
|
TIM1->BDTR = (8<<TIM_BDTR_DTG_Pos) | TIM_BDTR_MOE;
|
|
TIM1->DCR = (14<<TIM_DCR_DBA_Pos) | (1<<TIM_DCR_DBL_Pos);
|
|
TIM1->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 i = 0;
|
|
int j = 0;
|
|
int k = 0;
|
|
int n = 0;
|
|
while (23) {
|
|
if (USART1->ISR & USART_ISR_RXNE_RXFNE) {
|
|
usartbuf[usartp] = USART1->RDR;
|
|
usartp ++;
|
|
if (usartp >= sizeof(usartbuf)) {
|
|
usartp = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
{
|
|
i++;
|
|
j++;
|
|
i %= 6;
|
|
j %= 4;
|
|
delay_us(100000);
|
|
set_rj45_leds(1 << j);
|
|
set_status_leds(0x01);
|
|
if (i == 0) {
|
|
k++;
|
|
if (k == 10) {
|
|
k = 0;
|
|
n++;
|
|
if (n == 16) {
|
|
n = 0;
|
|
}
|
|
}
|
|
|
|
uint8_t b = (k < 8) ? (1<<k) : ~(1<<(k-8));
|
|
|
|
memset(tx_buf_write, 0, sizeof(*tx_buf_write));
|
|
for (size_t i=0; i<COUNT_OF(tx_buf_write->packet.channels); i++) {
|
|
tx_buf_write->packet.channels[i] = (k < 9) ? (1<<k) : 0xff;
|
|
}
|
|
for (size_t i=0; i<COUNT_OF(tx_buf_write->packet.brightness); i++) {
|
|
tx_buf_write->packet.brightness[i] = 0xff; //(n<<4) | n;
|
|
}
|
|
update_tx_buf();
|
|
}
|
|
}
|
|
}
|
|
|
|
void dma_tx_waveform(size_t table_size, const uint16_t *table) {
|
|
DMA1_Channel1->CCR = 0;
|
|
DMA1_Channel1->CCR = (1<<DMA_CCR_MSIZE_Pos) | (1<<DMA_CCR_PSIZE_Pos) | DMA_CCR_MINC | DMA_CCR_DIR | DMA_CCR_TCIE;
|
|
DMA1_Channel1->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<<DMA_CCR_MSIZE_Pos) | (1<<DMA_CCR_PSIZE_Pos) | DMA_CCR_DIR | DMA_CCR_TCIE;
|
|
DMA1_Channel1->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;
|
|
static int idle_symbol = 0;
|
|
|
|
if (DMA1->ISR & DMA_ISR_TEIF1) {
|
|
transfer_errors ++;
|
|
}
|
|
|
|
DMA1->IFCR = DMA_IFCR_CGIF1;
|
|
|
|
int bit = !!(current_symbol & (1<<tx_bitpos));
|
|
bit_arr[bit_pos++] = bit;
|
|
if (bit_pos == COUNT_OF(bit_arr)) {
|
|
bit_pos = 0;
|
|
}
|
|
|
|
if (tx_last_bit == bit) {
|
|
dma_tx_constant(COUNT_OF(waveform_zero_one), bit ? WAVEFORM_CONST_ONE : WAVEFORM_CONST_ZERO);
|
|
} else if (bit) {
|
|
dma_tx_waveform(COUNT_OF(waveform_zero_one), waveform_zero_one);
|
|
} else {
|
|
dma_tx_waveform(COUNT_OF(waveform_zero_one), waveform_one_zero);
|
|
}
|
|
|
|
tx_last_bit = bit;
|
|
|
|
if (tx_bitpos == 0) {
|
|
tx_bitpos = 9;
|
|
|
|
sym_arr[sym_pos] = -255;
|
|
|
|
idle_symbol++;
|
|
if (idle_symbol == 3) {
|
|
current_symbol = xfr_8b10b_encode(&encoder_state_8b10b, -K23_7);
|
|
idle_symbol = 0;
|
|
|
|
} else if (tx_sympos == sizeof(struct data_packet)) {
|
|
if (time_to_sync > 0) {
|
|
current_symbol = xfr_8b10b_encode(&encoder_state_8b10b, -K27_7);
|
|
sym_arr[sym_pos] = current_symbol;
|
|
time_to_sync--;
|
|
|
|
} else {
|
|
current_symbol = xfr_8b10b_encode(&encoder_state_8b10b, -K28_1);
|
|
sym_arr[sym_pos] = current_symbol;
|
|
packet_rng_state = xorshift32(1);
|
|
time_to_sync = SYNC_INTERVAL;
|
|
}
|
|
|
|
if (idle_buf_ready) {
|
|
union tx_buf_union *tmp = tx_buf_idle;
|
|
tx_buf_idle = tx_buf_read;
|
|
tx_buf_read = tmp;
|
|
idle_buf_ready = false;
|
|
}
|
|
|
|
tx_sympos = 0;
|
|
|
|
} else {
|
|
uint8_t b = tx_buf_read->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; i<offsetof(struct data_packet, crc); i++) {
|
|
crc = crc32_update(crc, tx_buf_write->bytes[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 () {
|
|
}
|
|
|