diff --git a/F0-nolib/Snippets/Readme.md b/F0-nolib/Snippets/Readme.md index 6cfa3bd..808ed80 100644 --- a/F0-nolib/Snippets/Readme.md +++ b/F0-nolib/Snippets/Readme.md @@ -2,3 +2,6 @@ Some snippets ============= * Flash_EEPROM - EEPROM emulation in flash +* Jump2Boot.c - software init of bootloader +* printuhex.c - print uint32_t in HEX +* readint.c - read integer number in any (bin/hex/dec) system diff --git a/F0-nolib/Snippets/readint.c b/F0-nolib/Snippets/readint.c new file mode 100644 index 0000000..70691c0 --- /dev/null +++ b/F0-nolib/Snippets/readint.c @@ -0,0 +1,77 @@ +char *omit_spaces(char *buf){ + while(*buf){ + if(*buf > ' ') break; + ++buf; + } + return buf; +} + +// THERE'S NO OVERFLOW PROTECTION IN NUMBER READ PROCEDURES! +// read decimal number +static char *getdec(char *buf, uint32_t *N){ + uint32_t num = 0; + while(*buf){ + char c = *buf; + if(c < '0' || c > '9'){ + break; + } + num *= 10; + num += c - '0'; + ++buf; + } + *N = num; + return buf; +} +// read hexadecimal number (without 0x prefix!) +static char *gethex(char *buf, uint32_t *N){ + uint32_t num = 0; + while(*buf){ + char c = *buf; + uint8_t M = 0; + if(c >= '0' && c <= '9'){ + M = '0'; + }else if(c >= 'A' && c <= 'F'){ + M = 'A' - 10; + }else if(c >= 'a' && c <= 'f'){ + M = 'a' - 10; + } + if(M){ + num <<= 4; + num += c - M; + }else{ + break; + } + ++buf; + } + *N = num; + return buf; +} +// read binary number (without 0b prefix!) +static char *getbin(char *buf, uint32_t *N){ + uint32_t num = 0; + while(*buf){ + char c = *buf; + if(c < '0' || c > '1'){ + break; + } + num <<= 1; + if(c == '1') num |= 1; + ++buf; + } + *N = num; + return buf; +} + +/** + * @brief getnum - read uint32_t from string (dec, hex or bin: 127, 0x7f, 0b1111111) + * @param buf - buffer with number and so on + * @param N - the number read + * @return pointer to first non-number symbol in buf (if it is == buf, there's no number) + */ +char *getnum(char *txt, uint32_t *N){ + if(*txt == '0'){ + if(txt[1] == 'x' || txt[1] == 'X') return gethex(txt+2, N); + if(txt[1] == 'b' || txt[1] == 'B') return getbin(txt+2, N); + } + return getdec(txt, N); +} diff --git a/F0-nolib/usbcdc/can.c b/F0-nolib/usbcdc/can.c index 860658d..2852b4c 100644 --- a/F0-nolib/usbcdc/can.c +++ b/F0-nolib/usbcdc/can.c @@ -168,13 +168,15 @@ void CAN_setup(uint16_t speed){ while((CAN->MSR & CAN_MSR_INAK)==CAN_MSR_INAK) if(--tmout == 0) break; /* (6) */ // accept ALL CAN->FMR = CAN_FMR_FINIT; /* (7) */ - CAN->FA1R = CAN_FA1R_FACT0; /* (8) */ + CAN->FA1R = CAN_FA1R_FACT0 | CAN_FA1R_FACT1; /* (8) */ // set to 1 all needed bits of CAN->FFA1R to switch given filters to FIFO1 #if 0 CAN->FM1R = CAN_FM1R_FBM0; /* (9) */ CAN->sFilterRegister[0].FR1 = CANID << 5 | ((BCAST_ID << 5) << 16); /* (10) */ #else - CAN->sFilterRegister[0].FR1 = 0; + CAN->sFilterRegister[0].FR1 = (1<<21)|(1<<5); // all odd IDs + CAN->FFA1R = 2; // filter 1 for FIFO1, filter 0 - for FIFO0 + CAN->sFilterRegister[1].FR1 = (1<<21); // all even IDs #endif CAN->FMR &=~ CAN_FMR_FINIT; /* (12) */ CAN->IER |= CAN_IER_ERRIE | CAN_IER_FOVIE0 | CAN_IER_FOVIE1; /* (13) */ @@ -352,6 +354,8 @@ static void can_process_fifo(uint8_t fifo_num){ uint8_t len = box->RDTR & 0x7; msg.length = len; msg.ID = box->RIR >> 21; + msg.filterNo = (box->RDTR >> 8) & 0xff; + msg.fifoNum = fifo_num; if(len){ // message can be without data uint32_t hb = box->RDHR, lb = box->RDLR; switch(len){ diff --git a/F0-nolib/usbcdc/can.h b/F0-nolib/usbcdc/can.h index 859d71a..6ff83eb 100644 --- a/F0-nolib/usbcdc/can.h +++ b/F0-nolib/usbcdc/can.h @@ -26,6 +26,9 @@ #include "hardware.h" +// amount of filter banks in STM32F0 +#define STM32F0FBANKNO 28 + // simple 1-byte commands #define CMD_TOGGLE (0xDA) #define CMD_BCAST (0xAD) @@ -45,6 +48,8 @@ typedef struct{ uint8_t data[8]; // up to 8 bytes of data uint8_t length; // data length + uint8_t filterNo; // filter number + uint8_t fifoNum; // message FIFO number uint16_t ID; // ID of receiver } CAN_message; diff --git a/F0-nolib/usbcdc/main.c b/F0-nolib/usbcdc/main.c index 2537e9b..b791b3b 100644 --- a/F0-nolib/usbcdc/main.c +++ b/F0-nolib/usbcdc/main.c @@ -137,6 +137,10 @@ int main(void){ switchbuff(3); SEND("got message, ID="); printuhex(can_mesg->ID); + SEND(", filter #"); + printu(can_mesg->filterNo); + SEND(", FIFO #"); + printu(can_mesg->fifoNum); SEND(", len="); printu(len); SEND(", data: "); diff --git a/F0-nolib/usbcdc/proto.c b/F0-nolib/usbcdc/proto.c index df31e22..6521217 100644 --- a/F0-nolib/usbcdc/proto.c +++ b/F0-nolib/usbcdc/proto.c @@ -264,6 +264,154 @@ TRUE_INLINE void print_ign_buf(){ } } +// print ID/mask of CAN->sFilterRegister[x] half +static void printID(uint16_t FRn){ + if(FRn & 0x1f) return; // trash + printuhex(FRn >> 5); +} +/* +Can filtering: FSCx=0 (CAN->FS1R) -> 16-bit identifiers +CAN->FMR = (sb)<<8 | FINIT - init filter in starting bank sb +CAN->FFA1R FFAx = 1 -> FIFO1, 0 -> FIFO0 +CAN->FA1R FACTx=1 - filter active +MASK: FBMx=0 (CAN->FM1R), two filters (n in FR1 and n+1 in FR2) + ID: CAN->sFilterRegister[x].FRn[0..15] + MASK: CAN->sFilterRegister[x].FRn[16..31] + FR bits: STID[10:0] RTR IDE EXID[17:15] +LIST: FBMx=1, four filters (n&n+1 in FR1, n+2&n+3 in FR2) + IDn: CAN->sFilterRegister[x].FRn[0..15] + IDn+1: CAN->sFilterRegister[x].FRn[16..31] +*/ +TRUE_INLINE void list_filters(){ + uint32_t fa = CAN->FA1R, ctr = 0, mask = 1; + while(fa){ + if(fa & 1){ + SEND("Filter "); printu(ctr); SEND(", FIFO"); + if(CAN->FFA1R & mask) SEND("1"); + else SEND("0"); + SEND(" in "); + if(CAN->FM1R & mask){ // up to 4 filters in LIST mode + SEND("LIST mode, IDs: "); + printID(CAN->sFilterRegister[ctr].FR1 & 0xffff); + SEND(" "); + printID(CAN->sFilterRegister[ctr].FR1 >> 16); + SEND(" "); + printID(CAN->sFilterRegister[ctr].FR2 & 0xffff); + SEND(" "); + printID(CAN->sFilterRegister[ctr].FR2 >> 16); + }else{ // up to 2 filters in MASK mode + SEND("MASK mode: "); + if(!(CAN->sFilterRegister[ctr].FR1&0x1f)){ + SEND("ID="); printID(CAN->sFilterRegister[ctr].FR1 & 0xffff); + SEND(", MASK="); printID(CAN->sFilterRegister[ctr].FR1 >> 16); + SEND(" "); + } + if(!(CAN->sFilterRegister[ctr].FR2&0x1f)){ + SEND("ID="); printID(CAN->sFilterRegister[ctr].FR2 & 0xffff); + SEND(", MASK="); printID(CAN->sFilterRegister[ctr].FR2 >> 16); + } + } + newline(); + } + fa >>= 1; + ++ctr; + mask <<= 1; + } + sendbuf(); +} + +/** + * @brief add_filter - add/modify filter + * @param str - string in format "bank# FIFO# mode num0 .. num3" + * where bank# - 0..27 + * if there's nothing after bank# - delete filter + * FIFO# - 0,1 + * mode - 'I' for ID, 'M' for mask + * num0..num3 - IDs in ID mode, ID/MASK for mask mode + */ +static void add_filter(char *str){ + uint32_t N; + str = omit_spaces(str); + char *n = getnum(str, &N); + if(n == str){ + SEND("No bank# given"); + return; + } + if(N > STM32F0FBANKNO-1){ + SEND("bank# > 27"); + return; + } + uint8_t bankno = (uint8_t)N; + str = omit_spaces(n); + if(!*str){ // deactivate filter + SEND("Deactivate filters in bank "); + printu(bankno); + CAN->FMR = CAN_FMR_FINIT; + CAN->FA1R &= ~(1<FMR &=~ CAN_FMR_FINIT; + return; + } + uint8_t fifono = 0; + if(*str == '1') fifono = 1; + else if(*str != '0'){ + SEND("FIFO# is 0 or 1"); + return; + } + str = omit_spaces(str + 1); + char c = *str; + uint8_t mode = 0; // ID + if(c == 'M' || c == 'm') mode = 1; + else if(c != 'I' && c != 'i'){ + SEND("mode is 'M/m' for MASK and 'I/i' for IDLIST"); + return; + } + str = omit_spaces(str + 1); + uint32_t filters[4]; + uint32_t nfilt; + for(nfilt = 0; nfilt < 4; ++nfilt){ + n = getnum(str, &N); + if(n == str) break; + filters[nfilt] = N; + str = omit_spaces(n); + } + if(nfilt == 0){ + SEND("You should add at least one filter!"); + return; + } + if(mode && (nfilt&1)){ + SEND("In MASK mode you should point pairs of ID/MASK"); + return; + } + CAN->FMR = CAN_FMR_FINIT; + uint32_t mask = 1<FA1R |= mask; // activate given filter + if(fifono) CAN->FFA1R |= mask; // set FIFO number + else CAN->FFA1R &= ~mask; + if(mode) CAN->FM1R &= ~mask; // MASK + else CAN->FM1R |= mask; // LIST + uint32_t F1 = (0x8f<<16); + uint32_t F2 = (0x8f<<16); + // reset filter registers to wrong value + CAN->sFilterRegister[bankno].FR1 = (0x8f<<16) | 0x8f; + CAN->sFilterRegister[bankno].FR2 = (0x8f<<16) | 0x8f; + switch(nfilt){ + case 4: + F2 = filters[3] << 21; + // fallthrough + case 3: + CAN->sFilterRegister[bankno].FR2 = (F2 & 0xffff0000) | (filters[2] << 5); + // fallthrough + case 2: + F1 = filters[1] << 21; + // fallthrough + case 1: + CAN->sFilterRegister[bankno].FR1 = (F1 & 0xffff0000) | (filters[0] << 5); + } + CAN->FMR &=~ CAN_FMR_FINIT; + SEND("Added filter with "); + printu(nfilt); SEND(" parameters"); +} + /** * @brief cmd_parser - command parsing * @param txt - buffer with commands & data @@ -277,24 +425,26 @@ void cmd_parser(char *txt, uint8_t isUSB){ * parse long commands here */ switch(_1st){ - case 's': - case 'S': - sendCANcommand(txt + 1); + case 'a': + addIGN(txt + 1); goto eof; break; case 'b': CANini(txt + 1); goto eof; break; - case 'a': - addIGN(txt + 1); + case 'f': + add_filter(txt + 1); goto eof; + break; + case 's': + case 'S': + sendCANcommand(txt + 1); + goto eof; + break; } if(txt[1] != '\n') *txt = '?'; // help for wrong message length switch(_1st){ - case 'f': - transmit_tbuf(); - break; case 'B': can_send_broadcast(); break; @@ -315,6 +465,9 @@ void cmd_parser(char *txt, uint8_t isUSB){ printuhex(getCANID()); newline(); break; + case 'l': + list_filters(); + break; case 'p': print_ign_buf(); break; @@ -345,9 +498,10 @@ void cmd_parser(char *txt, uint8_t isUSB){ "'B' - send broadcast dummy byte\n" "'C' - send dummy byte over CAN\n" "'d' - delete ignore list\n" - "'f' - flush UART buffer\n" + "'f' - add/delete filter, format: bank# FIFO# mode(M/I) num0 [num1 [num2 [num3]]]\n" "'G' - get CAN address\n" "'I' - reinit CAN (with new address)\n" + "'l' - list all active filters\n" "'p' - print ignore buffer\n" "'R' - software reset\n" "'s/S' - send data over CAN: s ID byte0 .. byteN\n" diff --git a/F0-nolib/usbcdc/usbcan.bin b/F0-nolib/usbcdc/usbcan.bin index 374a6d1..fbe7f64 100755 Binary files a/F0-nolib/usbcdc/usbcan.bin and b/F0-nolib/usbcdc/usbcan.bin differ