diff --git a/F0-nolib/canbus/src/Makefile b/F0-nolib/canbus/src/Makefile index aae0b4e..691a4d5 100644 --- a/F0-nolib/canbus/src/Makefile +++ b/F0-nolib/canbus/src/Makefile @@ -8,7 +8,7 @@ MCU = F042x6 # hardware definitions DEFS += -DUSARTNUM=1 #DEFS += -DCHECK_TMOUT -#DEFS += -DEBUG +DEFS += -DEBUG # change this linking script depending on particular MCU model, # for example, if you have STM32F103VBT6, you should write: LDSCRIPT = ld/stm32f042k.ld @@ -55,7 +55,7 @@ LIB_DIR := $(INC_DIR)/ld ############################################################################### # C flags CFLAGS += -O2 -g -MD -D__thumb2__=1 -CFLAGS += -Wall -Wextra -Wshadow -Wimplicit-function-declaration +CFLAGS += -Wall -Werror -Wextra -Wshadow -Wimplicit-function-declaration CFLAGS += -Wredundant-decls $(INCLUDE) # -Wmissing-prototypes -Wstrict-prototypes CFLAGS += -fno-common -ffunction-sections -fdata-sections diff --git a/F0-nolib/canbus/src/can.c b/F0-nolib/canbus/src/can.c index 011d7db..49ff5f3 100644 --- a/F0-nolib/canbus/src/can.c +++ b/F0-nolib/canbus/src/can.c @@ -20,32 +20,91 @@ * MA 02110-1301, USA. * */ +#include // memcpy #include "can.h" #include "hardware.h" #include "usart.h" -#define CMD_TOGGLE (0xDA) -#define CAN_ID_MASK (0xFF70U) -#define CAN_ID1 (0x651U) -#define CAN_ID2 (0x652U) -#define FILTER_LIST (0) /* 0: filter mode = identifier mask, 1: filter mode = identifier list */ +#define CMD_TOGGLE (0xDA) +#define CAN_ID_MASK (0x7F8) +#define CAN_ID_PREFIX (0xAAA) +#define TARG_ID (CAN_ID_PREFIX & CAN_ID_MASK) -#define CAN_FLAG_GOTDUMMY (1) -static uint8_t CAN_addr = 255; +#define CAN_FLAG_GOTDUMMY (1) +// incoming message buffer size +#define CAN_INMESSAGE_SIZE (6) + +extern volatile uint32_t Tms; + +// circular buffer for received messages +static CAN_message messages[CAN_INMESSAGE_SIZE]; +static uint8_t first_free_idx = 0; // index of first empty cell +static int8_t first_nonfree_idx = -1; // index of first data cell + +static uint16_t CANID = 0xFFFF; static uint8_t CAN_flags = 0; +static uint32_t last_err_code = 0; +static CAN_status can_status = CAN_STOP; -// get CAN address data from GPIO pins -void readCANaddr(){ - CAN_addr = READ_CAN_INV_ADDR(); - CAN_addr = ~CAN_addr & 0x7; +static void can_process_fifo(uint8_t fifo_num); + +CAN_status CAN_get_status(){ + CAN_status st = can_status; + // give overrun message only once + if(st == CAN_FIFO_OVERRUN) can_status = CAN_READY; + return st; } -uint8_t getCANaddr(){ - return CAN_addr; +// push next message into buffer; return 1 if buffer overfull +static int CAN_messagebuf_push(CAN_message *msg){ + MSG("Try to push\n"); + if(first_free_idx == first_nonfree_idx) return 1; // no free space + memcpy(&messages[first_free_idx++], msg, sizeof(CAN_message)); + // need to roll? + if(first_free_idx == CAN_INMESSAGE_SIZE) first_free_idx = 0; + #ifdef EBUG + MSG("1st free: "); usart_putchar('0' + first_free_idx); newline(); + #endif + return 0; +} + +// pop message from buffer +CAN_message *CAN_messagebuf_pop(){ + if(first_nonfree_idx < 0) return NULL; + #ifdef EBUG + MSG("read from idx "); usart_putchar('0' + first_nonfree_idx); newline(); + #endif + CAN_message *msg = &messages[first_nonfree_idx++]; + if(first_nonfree_idx == CAN_INMESSAGE_SIZE) first_nonfree_idx = 0; + if(first_nonfree_idx == first_free_idx){ // buffer is empty - refresh it + first_nonfree_idx = -1; + first_free_idx = 0; + MSG("refresh buffer\n"); + } + return msg; +} + +// get CAN address data from GPIO pins +void readCANID(){ + uint8_t CAN_addr = READ_CAN_INV_ADDR(); + CAN_addr = ~CAN_addr & 0x7; + CANID = (CAN_ID_PREFIX & CAN_ID_MASK) | CAN_addr; +} + +uint16_t getCANID(){ + return CANID; +} + +void CAN_reinit(){ + readCANID(); + CAN->TSR |= CAN_TSR_ABRQ0 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ2; + RCC->APB1RSTR |= RCC_APB1RSTR_CANRST; + RCC->APB1RSTR &= ~RCC_APB1RSTR_CANRST; + CAN_setup(); } void CAN_setup(){ - if(CAN_addr == 255) readCANaddr(); + if(CANID == 0xFFFF) readCANID(); // Configure GPIO: PB8 - CAN_Rx, PB9 - CAN_Tx /* (1) Select AF mode (10) on PB8 and PB9 */ /* (2) AF4 for CAN signals */ @@ -59,23 +118,24 @@ void CAN_setup(){ /* (1) Enter CAN init mode to write the configuration */ /* (2) Wait the init mode entering */ /* (3) Exit sleep mode */ - /* (4) Loopback mode, set timing to 1Mb/s: BS1 = 4, BS2 = 3, prescaler = 6 */ + /* (4) Loopback mode, set timing to 100kb/s: BS1 = 4, BS2 = 3, prescaler = 60 */ /* (5) Leave init mode */ /* (6) Wait the init mode leaving */ /* (7) Enter filter init mode, (16-bit + mask, filter 0 for FIFO 0) */ /* (8) Acivate filter 0 */ /* (9) Identifier list mode */ - /* (11) Set the Id list */ - /* (12) Set the Id + mask (all bits of standard id will care) */ - /* (13) Leave filter init */ - /* (14) Set FIFO0 message pending IT enable */ + /* (10) Set the Id list */ + /* (12) Leave filter init */ + /* (13) Set error interrupts enable */ CAN->MCR |= CAN_MCR_INRQ; /* (1) */ while((CAN->MSR & CAN_MSR_INAK)!=CAN_MSR_INAK) /* (2) */ { /* add time out here for a robust application */ } CAN->MCR &=~ CAN_MCR_SLEEP; /* (3) */ - CAN->BTR |= CAN_BTR_LBKM | 2 << 20 | 3 << 16 | 5 << 0; /* (4) */ + CAN->MCR |= CAN_MCR_ABOM; + + CAN->BTR |= 2 << 20 | 3 << 16 | 59 << 0; /* (4) */ CAN->MCR &=~ CAN_MCR_INRQ; /* (5) */ while((CAN->MSR & CAN_MSR_INAK)==CAN_MSR_INAK) /* (6) */ { @@ -83,49 +143,191 @@ void CAN_setup(){ } CAN->FMR = CAN_FMR_FINIT; /* (7) */ CAN->FA1R = CAN_FA1R_FACT0; /* (8) */ - #if (FILTER_LIST) CAN->FM1R = CAN_FM1R_FBM0; /* (9) */ - CAN->sFilterRegister[0].FR1 = CAN_ID2 << 5 | CAN_ID1 << (16+5); /* (10) */ - #else - CAN->sFilterRegister[0].FR1 = CAN_ID1 << 5 | CAN_ID_MASK << 16; /* (11) */ - #endif /* FILTER_LIST */ + CAN->sFilterRegister[0].FR1 = CANID << 5; /* (10) */ CAN->FMR &=~ CAN_FMR_FINIT; /* (12) */ - CAN->IER |= CAN_IER_FMPIE0; /* (13) */ + CAN->IER |= CAN_IER_ERRIE | CAN_IER_FOVIE0 | CAN_IER_FOVIE1; /* (13) */ /* Configure IT */ /* (14) Set priority for CAN_IRQn */ /* (15) Enable CAN_IRQn */ - NVIC_SetPriority(CEC_CAN_IRQn, 0); /* (16) */ - NVIC_EnableIRQ(CEC_CAN_IRQn); /* (17) */ + NVIC_SetPriority(CEC_CAN_IRQn, 0); /* (14) */ + NVIC_EnableIRQ(CEC_CAN_IRQn); /* (15) */ + can_status = CAN_READY; } void can_proc(){ + if(last_err_code){ +#ifdef EBUG + MSG("Error, ESR="); + printu(last_err_code); + newline(); +#endif + last_err_code = 0; + } + // check for messages in FIFO0 & FIFO1 + if(CAN->RF0R & CAN_RF0R_FMP0){ + can_process_fifo(0); + } + if(CAN->RF1R & CAN_RF1R_FMP1){ + can_process_fifo(1); + } + if(CAN->ESR & (CAN_ESR_BOFF | CAN_ESR_EPVF | CAN_ESR_EWGF)){ // much errors - restart CAN BUS + MSG("bus-off, restarting\n"); + // request abort for all mailboxes + CAN->TSR |= CAN_TSR_ABRQ0 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ2; + // reset CAN bus + RCC->APB1RSTR |= RCC_APB1RSTR_CANRST; + RCC->APB1RSTR &= ~RCC_APB1RSTR_CANRST; + CAN_setup(); + } if(CAN_flags){ if(CAN_flags & CAN_FLAG_GOTDUMMY){ SEND("Got dummy message\n"); } CAN_flags = 0; } + LED_off(LED1); +#ifdef EBUG + static uint32_t esr, msr, tsr; + uint32_t msr_now = CAN->MSR & 0xf; + if(esr != CAN->ESR || msr != msr_now || tsr != CAN->TSR){ + MSG("Timestamp: "); + printu(Tms); + newline(); + } + if((CAN->ESR) != esr){ + usart_putchar(((CAN->ESR & CAN_ESR_BOFF) != 0) + '0'); + esr = CAN->ESR; + MSG("CAN->ESR: "); + printuhex(esr); newline(); + } + if(msr_now != msr){ + msr = msr_now; + MSG("CAN->MSR & 0xf: "); + printuhex(msr); newline(); + } + if(CAN->TSR != tsr){ + tsr = CAN->TSR; + MSG("CAN->TSR: "); + printuhex(tsr); newline(); + } +#endif +} + +CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id){ + uint8_t mailbox = 0; + // check first free mailbox + if(CAN->TSR & (CAN_TSR_TME)){ + mailbox = (CAN->TSR & CAN_TSR_CODE) >> 24; + #ifdef EBUG + MSG("select "); usart_putchar('0'+mailbox); SEND(" mailbox\n"); + #endif + }else{ // no free mailboxes + return CAN_BUSY; + } + CAN_TxMailBox_TypeDef *box = &CAN->sTxMailBox[mailbox]; + uint32_t lb = 0, hb = 0; + switch(len){ + case 8: + hb |= (uint32_t)msg[7] << 24; + case 7: + hb |= (uint32_t)msg[6] << 16; + case 6: + hb |= (uint32_t)msg[5] << 8; + case 5: + hb |= (uint32_t)msg[4]; + case 4: + lb |= (uint32_t)msg[3] << 24; + case 3: + lb |= (uint32_t)msg[2] << 16; + case 2: + lb |= (uint32_t)msg[1] << 8; + default: + lb |= (uint32_t)msg[0]; + } + box->TDLR = lb; + box->TDHR = hb; + box->TDTR = len; + box->TIR = (target_id & 0x7FF) << 21 | CAN_TI0R_TXRQ; + return CAN_OK; } void can_send_dummy(){ - if((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0){ /* check mailbox 0 is empty */ - CAN->sTxMailBox[0].TDTR = 1; /* fill data length = 1 */ - CAN->sTxMailBox[0].TDLR = CMD_TOGGLE; /* fill 8-bit data */ - CAN->sTxMailBox[0].TIR = (uint32_t)(CAN_ID1 << 21 | CAN_TI0R_TXRQ); /* fill Id field and request a transmission */ + uint8_t msg = CMD_TOGGLE; + if(CAN_OK != can_send(&msg, 1, TARG_ID)) SEND("Bus busy!\n"); + MSG("CAN->MSR: "); + printuhex(CAN->MSR); newline(); + MSG("CAN->TSR: "); + printuhex(CAN->TSR); newline(); + MSG("CAN->ESR: "); + printuhex(CAN->ESR); newline(); +} + +static void can_process_fifo(uint8_t fifo_num){ + if(fifo_num > 1) return; + LED_on(LED1); // Toggle LED1 + CAN_FIFOMailBox_TypeDef *box = &CAN->sFIFOMailBox[fifo_num]; + volatile uint32_t *RFxR = (fifo_num) ? &CAN->RF1R : &CAN->RF0R; + MSG("Receive, RDTR="); + #ifdef EBUG + printuhex(box->RDTR); + newline(); + #endif + // read all + while(*RFxR & CAN_RF0R_FMP0){ // amount of messages pending + // CAN_RDTxR: (16-31) - timestamp, (8-15) - filter match index, (0-3) - data length + /* TODO: check filter match index if more than one ID can receive */ + CAN_message msg; + uint8_t *dat = msg.data; + uint8_t len = box->RDTR & 0x7; + msg.length = len; + if(len){ // message can be without data + uint32_t hb = box->RDHR, lb = box->RDLR; + switch(len){ + case 8: + dat[7] = hb>>24; + case 7: + dat[6] = (hb>>16) & 0xff; + case 6: + dat[5] = (hb>>8) & 0xff; + case 5: + dat[4] = hb & 0xff; + case 4: + dat[3] = lb>>24; + case 3: + dat[2] = (lb>>16) & 0xff; + case 2: + dat[1] = (lb>>8) & 0xff; + case 1: + dat[0] = lb & 0xff; + } + } + if(CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later + *RFxR |= CAN_RF0R_RFOM0; // release fifo for access to next message } + if(*RFxR & CAN_RF0R_FULL0) *RFxR &= ~CAN_RF0R_FULL0; } void cec_can_isr(){ - uint32_t CAN_ReceiveMessage = 0; - - if(CAN->RF0R & CAN_RF0R_FMP0){ /* check if a message is filtered and received by FIFO 0 */ - LED_blink(LED1); /* Toggle LED1 */ - CAN_ReceiveMessage = CAN->sFIFOMailBox[0].RDLR; /* read data */ - CAN->RF0R |= CAN_RF0R_RFOM0; /* release FIFO */ - if((CAN_ReceiveMessage & 0xFF) == CMD_TOGGLE){ - CAN_flags |= CAN_FLAG_GOTDUMMY; - } + if(CAN->RF0R & CAN_RF0R_FOVR0){ // FIFO overrun + CAN->RF0R &= ~CAN_RF0R_FOVR0; + can_status = CAN_FIFO_OVERRUN; + } + if(CAN->RF1R & CAN_RF1R_FOVR1){ + CAN->RF1R &= ~CAN_RF1R_FOVR1; + can_status = CAN_FIFO_OVERRUN; + } + #ifdef EBUG + if(can_status == CAN_FIFO_OVERRUN) MSG("fifo 0 overrun\n"); + #endif + if(CAN->MSR & CAN_MSR_ERRI){ // Error + CAN->MSR &= ~CAN_MSR_ERRI; + // request abort for problem mailbox + if(CAN->TSR & CAN_TSR_TERR0) CAN->TSR |= CAN_TSR_ABRQ0; + if(CAN->TSR & CAN_TSR_TERR1) CAN->TSR |= CAN_TSR_ABRQ1; + if(CAN->TSR & CAN_TSR_TERR2) CAN->TSR |= CAN_TSR_ABRQ2; + last_err_code = CAN->ESR; } } diff --git a/F0-nolib/canbus/src/can.h b/F0-nolib/canbus/src/can.h index 3e381a8..c21f7db 100644 --- a/F0-nolib/canbus/src/can.h +++ b/F0-nolib/canbus/src/can.h @@ -26,12 +26,30 @@ #include "hardware.h" -void readCANaddr(); -uint8_t getCANaddr(); +typedef struct{ + uint8_t data[8]; + uint8_t length; +} CAN_message; +typedef enum{ + CAN_STOP, + CAN_READY, + CAN_BUSY, + CAN_OK, + CAN_FIFO_OVERRUN +} CAN_status; + +CAN_status CAN_get_status(); + +void readCANID(); +uint16_t getCANID(); + +void CAN_reinit(); void CAN_setup(); void can_send_dummy(); void can_proc(); +CAN_message *CAN_messagebuf_pop(); + #endif // __CAN_H__ diff --git a/F0-nolib/canbus/src/canbus.bin b/F0-nolib/canbus/src/canbus.bin index 9a85c3c..ef66d7b 100755 Binary files a/F0-nolib/canbus/src/canbus.bin and b/F0-nolib/canbus/src/canbus.bin differ diff --git a/F0-nolib/canbus/src/hardware.h b/F0-nolib/canbus/src/hardware.h index 322653b..56f152e 100644 --- a/F0-nolib/canbus/src/hardware.h +++ b/F0-nolib/canbus/src/hardware.h @@ -41,7 +41,9 @@ #define LED1_port GPIOC #define LED1_pin (1<<14) -#define LED_blink(x) pin_toggle(x ## _port, x ## _pin) +#define LED_blink(x) pin_toggle(x ## _port, x ## _pin) +#define LED_on(x) pin_clear(x ## _port, x ## _pin) +#define LED_off(x) pin_set(x ## _port, x ## _pin) // CAN address - PB14(0), PB15(1), PA8(2) diff --git a/F0-nolib/canbus/src/main.c b/F0-nolib/canbus/src/main.c index 11a0d59..a5f32f3 100644 --- a/F0-nolib/canbus/src/main.c +++ b/F0-nolib/canbus/src/main.c @@ -53,6 +53,8 @@ void iwdg_setup(){ int main(void){ uint32_t lastT = 0; + uint8_t ctr, len; + CAN_message *can_mesg; int L; char *txt; sysreset(); @@ -60,12 +62,13 @@ int main(void){ gpio_setup(); usart_setup(); iwdg_setup(); - readCANaddr(); + readCANID(); CAN_setup(); SEND("Greetings! My address is "); - printu(getCANaddr()); + printuhex(getCANID()); newline(); + if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured SEND("WDGRESET=1\n"); } @@ -81,6 +84,20 @@ int main(void){ lastT = Tms; } can_proc(); + if(CAN_get_status() == CAN_FIFO_OVERRUN){ + SEND("CAN bus fifo overrun occured!\n"); + } + can_mesg = CAN_messagebuf_pop(); + if(can_mesg){ // new data in buff + len = can_mesg->length; + SEND("got message, len: "); usart_putchar('0' + len); + SEND(", data: "); + for(ctr = 0; ctr < len; ++ctr){ + printuhex(can_mesg->data[ctr]); + usart_putchar(' '); + } + newline(); + } if(usartrx()){ // usart1 received data, store in in buffer L = usart_getline(&txt); char _1st = txt[0]; @@ -92,12 +109,19 @@ int main(void){ break; case 'G': SEND("Can address: "); - printu(getCANaddr()); + printuhex(getCANID()); newline(); break; case 'R': + SEND("Soft reset\n"); NVIC_SystemReset(); break; + case 'S': + CAN_reinit(); + SEND("Can address: "); + printuhex(getCANID()); + newline(); + break; case 'W': SEND("Wait for reboot\n"); while(1){nop();}; @@ -107,6 +131,7 @@ int main(void){ "'C' - send dummy byte over CAN\n" "'G' - get CAN address\n" "'R' - software reset\n" + "'S' - reinit CAN (with new address)\n" "'W' - test watchdog\n" ); break; diff --git a/F0-nolib/canbus/src/usart.c b/F0-nolib/canbus/src/usart.c index 47c5e44..64b6fc3 100644 --- a/F0-nolib/canbus/src/usart.c +++ b/F0-nolib/canbus/src/usart.c @@ -218,6 +218,20 @@ void printu(uint32_t val){ while(LINE_BUSY == usart_send_blocking(bufa, l+bpos)); } +// print 32bit unsigned int as hex +void printuhex(uint32_t val){ + SEND("0x"); + uint8_t *ptr = (uint8_t*)&val + 3; + int i, j; + for(i = 0; i < 4; ++i, --ptr){ + for(j = 1; j > -1; --j){ + uint8_t half = (*ptr >> (4*j)) & 0x0f; + if(half < 10) usart_putchar(half + '0'); + else usart_putchar(half - 10 + 'a'); + } + } +} + #if USARTNUM == 2 void dma1_channel4_5_isr(){ if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx diff --git a/F0-nolib/canbus/src/usart.h b/F0-nolib/canbus/src/usart.h index f1d1d50..ae2da2e 100644 --- a/F0-nolib/canbus/src/usart.h +++ b/F0-nolib/canbus/src/usart.h @@ -56,5 +56,6 @@ TXstatus usart_send_blocking(const char *str, int len); void newline(); void usart_putchar(const char ch); void printu(uint32_t val); +void printuhex(uint32_t val); #endif // __USART_H__