add more universal functions for reading/writing CAN

This commit is contained in:
eddyem 2018-06-24 14:42:05 +03:00
parent 9d9536eb2b
commit c40e239b19
8 changed files with 311 additions and 49 deletions

View File

@ -8,7 +8,7 @@ MCU = F042x6
# hardware definitions # hardware definitions
DEFS += -DUSARTNUM=1 DEFS += -DUSARTNUM=1
#DEFS += -DCHECK_TMOUT #DEFS += -DCHECK_TMOUT
#DEFS += -DEBUG DEFS += -DEBUG
# change this linking script depending on particular MCU model, # change this linking script depending on particular MCU model,
# for example, if you have STM32F103VBT6, you should write: # for example, if you have STM32F103VBT6, you should write:
LDSCRIPT = ld/stm32f042k.ld LDSCRIPT = ld/stm32f042k.ld
@ -55,7 +55,7 @@ LIB_DIR := $(INC_DIR)/ld
############################################################################### ###############################################################################
# C flags # C flags
CFLAGS += -O2 -g -MD -D__thumb2__=1 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) CFLAGS += -Wredundant-decls $(INCLUDE)
# -Wmissing-prototypes -Wstrict-prototypes # -Wmissing-prototypes -Wstrict-prototypes
CFLAGS += -fno-common -ffunction-sections -fdata-sections CFLAGS += -fno-common -ffunction-sections -fdata-sections

View File

@ -20,32 +20,91 @@
* MA 02110-1301, USA. * MA 02110-1301, USA.
* *
*/ */
#include <string.h> // memcpy
#include "can.h" #include "can.h"
#include "hardware.h" #include "hardware.h"
#include "usart.h" #include "usart.h"
#define CMD_TOGGLE (0xDA) #define CMD_TOGGLE (0xDA)
#define CAN_ID_MASK (0xFF70U) #define CAN_ID_MASK (0x7F8)
#define CAN_ID1 (0x651U) #define CAN_ID_PREFIX (0xAAA)
#define CAN_ID2 (0x652U) #define TARG_ID (CAN_ID_PREFIX & CAN_ID_MASK)
#define FILTER_LIST (0) /* 0: filter mode = identifier mask, 1: filter mode = identifier list */
#define CAN_FLAG_GOTDUMMY (1) #define CAN_FLAG_GOTDUMMY (1)
static uint8_t CAN_addr = 255; // 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 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 static void can_process_fifo(uint8_t fifo_num);
void readCANaddr(){
CAN_addr = READ_CAN_INV_ADDR(); CAN_status CAN_get_status(){
CAN_addr = ~CAN_addr & 0x7; CAN_status st = can_status;
// give overrun message only once
if(st == CAN_FIFO_OVERRUN) can_status = CAN_READY;
return st;
} }
uint8_t getCANaddr(){ // push next message into buffer; return 1 if buffer overfull
return CAN_addr; 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(){ void CAN_setup(){
if(CAN_addr == 255) readCANaddr(); if(CANID == 0xFFFF) readCANID();
// Configure GPIO: PB8 - CAN_Rx, PB9 - CAN_Tx // Configure GPIO: PB8 - CAN_Rx, PB9 - CAN_Tx
/* (1) Select AF mode (10) on PB8 and PB9 */ /* (1) Select AF mode (10) on PB8 and PB9 */
/* (2) AF4 for CAN signals */ /* (2) AF4 for CAN signals */
@ -59,23 +118,24 @@ void CAN_setup(){
/* (1) Enter CAN init mode to write the configuration */ /* (1) Enter CAN init mode to write the configuration */
/* (2) Wait the init mode entering */ /* (2) Wait the init mode entering */
/* (3) Exit sleep mode */ /* (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 */ /* (5) Leave init mode */
/* (6) Wait the init mode leaving */ /* (6) Wait the init mode leaving */
/* (7) Enter filter init mode, (16-bit + mask, filter 0 for FIFO 0) */ /* (7) Enter filter init mode, (16-bit + mask, filter 0 for FIFO 0) */
/* (8) Acivate filter 0 */ /* (8) Acivate filter 0 */
/* (9) Identifier list mode */ /* (9) Identifier list mode */
/* (11) Set the Id list */ /* (10) Set the Id list */
/* (12) Set the Id + mask (all bits of standard id will care) */ /* (12) Leave filter init */
/* (13) Leave filter init */ /* (13) Set error interrupts enable */
/* (14) Set FIFO0 message pending IT enable */
CAN->MCR |= CAN_MCR_INRQ; /* (1) */ CAN->MCR |= CAN_MCR_INRQ; /* (1) */
while((CAN->MSR & CAN_MSR_INAK)!=CAN_MSR_INAK) /* (2) */ while((CAN->MSR & CAN_MSR_INAK)!=CAN_MSR_INAK) /* (2) */
{ {
/* add time out here for a robust application */ /* add time out here for a robust application */
} }
CAN->MCR &=~ CAN_MCR_SLEEP; /* (3) */ 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) */ CAN->MCR &=~ CAN_MCR_INRQ; /* (5) */
while((CAN->MSR & CAN_MSR_INAK)==CAN_MSR_INAK) /* (6) */ while((CAN->MSR & CAN_MSR_INAK)==CAN_MSR_INAK) /* (6) */
{ {
@ -83,49 +143,191 @@ void CAN_setup(){
} }
CAN->FMR = CAN_FMR_FINIT; /* (7) */ CAN->FMR = CAN_FMR_FINIT; /* (7) */
CAN->FA1R = CAN_FA1R_FACT0; /* (8) */ CAN->FA1R = CAN_FA1R_FACT0; /* (8) */
#if (FILTER_LIST)
CAN->FM1R = CAN_FM1R_FBM0; /* (9) */ CAN->FM1R = CAN_FM1R_FBM0; /* (9) */
CAN->sFilterRegister[0].FR1 = CAN_ID2 << 5 | CAN_ID1 << (16+5); /* (10) */ CAN->sFilterRegister[0].FR1 = CANID << 5; /* (10) */
#else
CAN->sFilterRegister[0].FR1 = CAN_ID1 << 5 | CAN_ID_MASK << 16; /* (11) */
#endif /* FILTER_LIST */
CAN->FMR &=~ CAN_FMR_FINIT; /* (12) */ 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 */ /* Configure IT */
/* (14) Set priority for CAN_IRQn */ /* (14) Set priority for CAN_IRQn */
/* (15) Enable CAN_IRQn */ /* (15) Enable CAN_IRQn */
NVIC_SetPriority(CEC_CAN_IRQn, 0); /* (16) */ NVIC_SetPriority(CEC_CAN_IRQn, 0); /* (14) */
NVIC_EnableIRQ(CEC_CAN_IRQn); /* (17) */ NVIC_EnableIRQ(CEC_CAN_IRQn); /* (15) */
can_status = CAN_READY;
} }
void can_proc(){ 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){
if(CAN_flags & CAN_FLAG_GOTDUMMY){ if(CAN_flags & CAN_FLAG_GOTDUMMY){
SEND("Got dummy message\n"); SEND("Got dummy message\n");
} }
CAN_flags = 0; 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(){ void can_send_dummy(){
if((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0){ /* check mailbox 0 is empty */ uint8_t msg = CMD_TOGGLE;
CAN->sTxMailBox[0].TDTR = 1; /* fill data length = 1 */ if(CAN_OK != can_send(&msg, 1, TARG_ID)) SEND("Bus busy!\n");
CAN->sTxMailBox[0].TDLR = CMD_TOGGLE; /* fill 8-bit data */ MSG("CAN->MSR: ");
CAN->sTxMailBox[0].TIR = (uint32_t)(CAN_ID1 << 21 | CAN_TI0R_TXRQ); /* fill Id field and request a transmission */ 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(){ void cec_can_isr(){
uint32_t CAN_ReceiveMessage = 0; if(CAN->RF0R & CAN_RF0R_FOVR0){ // FIFO overrun
CAN->RF0R &= ~CAN_RF0R_FOVR0;
if(CAN->RF0R & CAN_RF0R_FMP0){ /* check if a message is filtered and received by FIFO 0 */ can_status = CAN_FIFO_OVERRUN;
LED_blink(LED1); /* Toggle LED1 */ }
CAN_ReceiveMessage = CAN->sFIFOMailBox[0].RDLR; /* read data */ if(CAN->RF1R & CAN_RF1R_FOVR1){
CAN->RF0R |= CAN_RF0R_RFOM0; /* release FIFO */ CAN->RF1R &= ~CAN_RF1R_FOVR1;
if((CAN_ReceiveMessage & 0xFF) == CMD_TOGGLE){ can_status = CAN_FIFO_OVERRUN;
CAN_flags |= CAN_FLAG_GOTDUMMY; }
} #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;
} }
} }

View File

@ -26,12 +26,30 @@
#include "hardware.h" #include "hardware.h"
void readCANaddr(); typedef struct{
uint8_t getCANaddr(); 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_setup();
void can_send_dummy(); void can_send_dummy();
void can_proc(); void can_proc();
CAN_message *CAN_messagebuf_pop();
#endif // __CAN_H__ #endif // __CAN_H__

Binary file not shown.

View File

@ -41,7 +41,9 @@
#define LED1_port GPIOC #define LED1_port GPIOC
#define LED1_pin (1<<14) #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) // CAN address - PB14(0), PB15(1), PA8(2)

View File

@ -53,6 +53,8 @@ void iwdg_setup(){
int main(void){ int main(void){
uint32_t lastT = 0; uint32_t lastT = 0;
uint8_t ctr, len;
CAN_message *can_mesg;
int L; int L;
char *txt; char *txt;
sysreset(); sysreset();
@ -60,12 +62,13 @@ int main(void){
gpio_setup(); gpio_setup();
usart_setup(); usart_setup();
iwdg_setup(); iwdg_setup();
readCANaddr(); readCANID();
CAN_setup(); CAN_setup();
SEND("Greetings! My address is "); SEND("Greetings! My address is ");
printu(getCANaddr()); printuhex(getCANID());
newline(); newline();
if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured
SEND("WDGRESET=1\n"); SEND("WDGRESET=1\n");
} }
@ -81,6 +84,20 @@ int main(void){
lastT = Tms; lastT = Tms;
} }
can_proc(); 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 if(usartrx()){ // usart1 received data, store in in buffer
L = usart_getline(&txt); L = usart_getline(&txt);
char _1st = txt[0]; char _1st = txt[0];
@ -92,12 +109,19 @@ int main(void){
break; break;
case 'G': case 'G':
SEND("Can address: "); SEND("Can address: ");
printu(getCANaddr()); printuhex(getCANID());
newline(); newline();
break; break;
case 'R': case 'R':
SEND("Soft reset\n");
NVIC_SystemReset(); NVIC_SystemReset();
break; break;
case 'S':
CAN_reinit();
SEND("Can address: ");
printuhex(getCANID());
newline();
break;
case 'W': case 'W':
SEND("Wait for reboot\n"); SEND("Wait for reboot\n");
while(1){nop();}; while(1){nop();};
@ -107,6 +131,7 @@ int main(void){
"'C' - send dummy byte over CAN\n" "'C' - send dummy byte over CAN\n"
"'G' - get CAN address\n" "'G' - get CAN address\n"
"'R' - software reset\n" "'R' - software reset\n"
"'S' - reinit CAN (with new address)\n"
"'W' - test watchdog\n" "'W' - test watchdog\n"
); );
break; break;

View File

@ -218,6 +218,20 @@ void printu(uint32_t val){
while(LINE_BUSY == usart_send_blocking(bufa, l+bpos)); 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 #if USARTNUM == 2
void dma1_channel4_5_isr(){ void dma1_channel4_5_isr(){
if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx

View File

@ -56,5 +56,6 @@ TXstatus usart_send_blocking(const char *str, int len);
void newline(); void newline();
void usart_putchar(const char ch); void usart_putchar(const char ch);
void printu(uint32_t val); void printu(uint32_t val);
void printuhex(uint32_t val);
#endif // __USART_H__ #endif // __USART_H__