From 131f6fab44e728b4749e0145c71743b473a2654f Mon Sep 17 00:00:00 2001 From: eddyem Date: Sat, 18 Apr 2020 20:11:59 +0300 Subject: [PATCH] SteppersCAN: add CAN & start working on steppers --- F0-nolib/CANbus_stepper/src/Makefile | 4 +- F0-nolib/CANbus_stepper/src/Readme.md | 57 ++++ F0-nolib/CANbus_stepper/src/can.c | 356 +++++++++++++++++++ F0-nolib/CANbus_stepper/src/can.h | 89 +++++ F0-nolib/CANbus_stepper/src/can_process.c | 101 ++++++ F0-nolib/CANbus_stepper/src/can_process.h | 38 +++ F0-nolib/CANbus_stepper/src/canstepper.bin | Bin 7812 -> 13776 bytes F0-nolib/CANbus_stepper/src/flash.c | 235 +++++++++++++ F0-nolib/CANbus_stepper/src/flash.h | 51 +++ F0-nolib/CANbus_stepper/src/hardware.c | 58 +++- F0-nolib/CANbus_stepper/src/hardware.h | 57 +++- F0-nolib/CANbus_stepper/src/main.c | 70 ++-- F0-nolib/CANbus_stepper/src/proto.c | 379 ++++++++++++++++----- F0-nolib/CANbus_stepper/src/proto.h | 8 +- F0-nolib/CANbus_stepper/src/steppers.c | 104 ++++++ F0-nolib/CANbus_stepper/src/steppers.h | 36 ++ F0-nolib/CANbus_stepper/src/usb.c | 236 ++++++------- F0-nolib/CANbus_stepper/src/usb.h | 10 +- F0-nolib/CANbus_stepper/src/usb_defs.h | 24 +- F0-nolib/CANbus_stepper/src/usb_lib.c | 160 ++++----- F0-nolib/CANbus_stepper/src/usb_lib.h | 63 ++-- F0-nolib/Snippets/Flash_EEPROM/flash.c | 267 +++++++++------ F0-nolib/Snippets/Flash_EEPROM/flash.h | 32 +- F0-nolib/Snippets/printuhex.c | 1 - F0-nolib/inc/Fx/stm32f0.h | 5 + F0-nolib/inc/ld/stm32f01234.ld | 3 +- F0-nolib/usbcdc/can.c | 2 +- F0-nolib/usbcdc/proto.c | 3 +- F0-nolib/usbcdc/usbcan.bin | Bin 13504 -> 13456 bytes 29 files changed, 1939 insertions(+), 510 deletions(-) create mode 100644 F0-nolib/CANbus_stepper/src/can.c create mode 100644 F0-nolib/CANbus_stepper/src/can.h create mode 100644 F0-nolib/CANbus_stepper/src/can_process.c create mode 100644 F0-nolib/CANbus_stepper/src/can_process.h mode change 100644 => 100755 F0-nolib/CANbus_stepper/src/canstepper.bin create mode 100644 F0-nolib/CANbus_stepper/src/flash.c create mode 100644 F0-nolib/CANbus_stepper/src/flash.h create mode 100644 F0-nolib/CANbus_stepper/src/steppers.c create mode 100644 F0-nolib/CANbus_stepper/src/steppers.h diff --git a/F0-nolib/CANbus_stepper/src/Makefile b/F0-nolib/CANbus_stepper/src/Makefile index e21163d..a4f0cf7 100644 --- a/F0-nolib/CANbus_stepper/src/Makefile +++ b/F0-nolib/CANbus_stepper/src/Makefile @@ -45,9 +45,9 @@ OBJS += $(STARTUP) # dependencies: we need them to recompile files if their headers-dependencies changed DEPS := $(OBJS:.o=.d) -INC_DIR ?= ../inc +INC_DIR ?= ../../inc -INCLUDE := -I$(INC_DIR)/F0 -I$(INC_DIR)/cm +INCLUDE := -I$(INC_DIR)/Fx -I$(INC_DIR)/cm LIB_DIR := $(INC_DIR)/ld ############################################################################### diff --git a/F0-nolib/CANbus_stepper/src/Readme.md b/F0-nolib/CANbus_stepper/src/Readme.md index 364dd7e..df4bf74 100644 --- a/F0-nolib/CANbus_stepper/src/Readme.md +++ b/F0-nolib/CANbus_stepper/src/Readme.md @@ -2,3 +2,60 @@ Development board for TMC2130/DRV8825 stepper driver modules ============================================================ Stepper control over CAN bus, RS-485 and USB. + +Pinout +====== + +PA0 - AIN0 (12V voltage control) AIN +PA1 - AIN1 (5V voltage control) AIN +PA3 - STEP timer +PA4 - DIR PP +PA5 - SCK - CFG1 - microstepping1 SPI/PP +PA6 - MISO - CFG0 - ~RST SPI/PP +PA7 - MOSI - CFG1 - microstepping0 SPI/PP +PA8 - Tx|Rx (RS485 direction) PP +PA9 - Tx (RS485) USART +PA10 - Rx (RS485) USART +PA11 - DM (USB) USB +PA12 - DP (USB) USB +PA13 - SWDIO (st-link) SWD +PA14 - SWCLK (st-link) SWD + +PB0 - ESW0 PUin +PB1 - ESW1 (limit switches or other inputs) PUin +PB2 - ESW2 PUin +PB8 - CAN_Rx (CAN) CAN +PB9 - CAN_Tx (CAN) CAN +PB10 - ESW3 PUin +PB12 - brdaddr0 PUin +PB13 - brdaddr1 (bits of board address switch) PUin +PB14 - brdaddr2 PUin +PB15 - brdaddr3 PUin + +PC13 - CFG6 - ~EN PP +PC14 - CFG3 - ~CS - microstepping2 PP +PC15 - ~SLEEP PP + +PF0 - VIO_on (turn ON Vdd of driver 4988 or 2130) OD +PF1 - ~FAULT (~fault output of 8825) FLin + +RS-485 +====== + +The same protocol as USB, but 1st symbol should be BRDADDR + + +CAN +=== + +Data format: big-endian. For example 0x03 0x04 0x05 0x0a means 0x0304050a. +Messages with variable width. +IN messages have ID = 0x70 | (devNo<<1), devNo - number, selected by jumpers @ board. +OUT messages have ID=IN+1. +zeros byte of data is command. All other - data. + + +TODO +==== + +Add linecoding_handler to change RS-485 speed due to USB connection settings? diff --git a/F0-nolib/CANbus_stepper/src/can.c b/F0-nolib/CANbus_stepper/src/can.c new file mode 100644 index 0000000..5439343 --- /dev/null +++ b/F0-nolib/CANbus_stepper/src/can.c @@ -0,0 +1,356 @@ +/* + * geany_encoding=koi8-r + * can.c + * + * Copyright 2018 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ +#include "can.h" +#include "hardware.h" +#include "proto.h" +#include "usart.h" + +#include // memcpy + +// 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 oldspeed = 100; // speed of last init + +static uint16_t CANID = 0xFFFF; +uint16_t masterID = 0; +static CAN_status can_status = CAN_STOP; + +static void can_process_fifo(uint8_t fifo_num); + +//static CAN_message loc_flood_msg; +//static CAN_message *flood_msg = NULL; // == loc_flood_msg - to flood + +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; +} + +// 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 + if(first_nonfree_idx < 0) first_nonfree_idx = 0; // first message in empty buffer + memcpy(&messages[first_free_idx++], msg, sizeof(CAN_message)); + // need to roll? + if(first_free_idx == CAN_INMESSAGE_SIZE) first_free_idx = 0; + return 0; +} + +// pop message from buffer +CAN_message *CAN_messagebuf_pop(){ + if(first_nonfree_idx < 0) return NULL; + 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; + } + return msg; +} + +// get CAN address data from GPIO pins +void readCANID(){ + uint8_t CAN_addr = refreshBRDaddr(); + CANID = (CAN_ID_PREFIX & CAN_ID_MASK) | (CAN_addr << 1); + masterID = CANID + 1; +} + +uint16_t getCANID(){ + return CANID; +} + +void CAN_reinit(uint16_t speed){ + readCANID(); + CAN->TSR |= CAN_TSR_ABRQ0 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ2; + RCC->APB1RSTR |= RCC_APB1RSTR_CANRST; + RCC->APB1RSTR &= ~RCC_APB1RSTR_CANRST; + CAN_setup(speed); +} + +/* +Can filtering: FSCx=0 (CAN->FS1R) -> 16-bit identifiers +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] +*/ + +/* +Can timing: main freq - APB (PLL=48MHz) +segment = 1sync + TBS1 + TBS2, sample point is between TBS1 and TBS2, +so if TBS1=4 and TBS2=3, sum=8, bit sampling freq is 48/8 = 6MHz +-> to get 100kbps we need prescaler=60 + 250kbps - 24 + 500kbps - 12 + 1MBps - 6 +*/ + +// speed - in kbps +void CAN_setup(uint16_t speed){ + if(speed == 0) speed = oldspeed; + else if(speed < 50) speed = 50; + else if(speed > 3000) speed = 3000; + oldspeed = speed; + uint32_t tmout = 16000000; + 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 */ + GPIOB->MODER = (GPIOB->MODER & ~(GPIO_MODER_MODER8 | GPIO_MODER_MODER9)) + | (GPIO_MODER_MODER8_AF | GPIO_MODER_MODER9_AF); /* (1) */ + GPIOB->AFR[1] = (GPIOB->AFR[1] &~ (GPIO_AFRH_AFRH0 | GPIO_AFRH_AFRH1))\ + | (4 << (0 * 4)) | (4 << (1 * 4)); /* (2) */ + /* Enable the peripheral clock CAN */ + RCC->APB1ENR |= RCC_APB1ENR_CANEN; + /* Configure CAN */ + /* (1) Enter CAN init mode to write the configuration */ + /* (2) Wait the init mode entering */ + /* (3) Exit sleep mode */ + /* (4) Normal mode, set timing to 100kb/s: TBS1 = 4, TBS2 = 3, prescaler = 60 */ + /* (5) Leave init mode */ + /* (6) Wait the init mode leaving */ + /* (13) Set error interrupts enable */ + CAN->MCR |= CAN_MCR_INRQ; /* (1) */ + while((CAN->MSR & CAN_MSR_INAK)!=CAN_MSR_INAK) /* (2) */ + { + if(--tmout == 0) break; + } + CAN->MCR &=~ CAN_MCR_SLEEP; /* (3) */ + CAN->MCR |= CAN_MCR_ABOM; /* allow automatically bus-off */ + + CAN->BTR |= 2 << 20 | 3 << 16 | (6000/speed) << 0; /* (4) */ + CAN->MCR &=~ CAN_MCR_INRQ; /* (5) */ + tmout = 16000000; + while((CAN->MSR & CAN_MSR_INAK)==CAN_MSR_INAK) if(--tmout == 0) break; /* (6) */ + // init filter: accept data only for this board + can_accept_one(); + + 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); /* (14) */ + NVIC_EnableIRQ(CEC_CAN_IRQn); /* (15) */ + can_status = CAN_READY; +} + +void can_proc(){ + // 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); + } + IWDG->KR = IWDG_REFRESH; + if(CAN->ESR & (CAN_ESR_BOFF | CAN_ESR_EPVF | CAN_ESR_EWGF)){ // much errors - restart CAN BUS + SEND("\nToo much errors, restarting CAN!\n"); + SEND("Receive error counter: "); + printu((CAN->ESR & CAN_ESR_REC)>>24); + SEND("\nTransmit error counter: "); + printu((CAN->ESR & CAN_ESR_TEC)>>16); + SEND("\nLast error code: "); + int lec = (CAN->ESR & CAN_ESR_LEC) >> 4; + const char *errmsg = "No"; + switch(lec){ + case 1: errmsg = "Stuff"; break; + case 2: errmsg = "Form"; break; + case 3: errmsg = "Ack"; break; + case 4: errmsg = "Bit recessive"; break; + case 5: errmsg = "Bit dominant"; break; + case 6: errmsg = "CRC"; break; + case 7: errmsg = "(set by software)"; break; + } + SEND(errmsg); SEND(" error\n"); + if(CAN->ESR & CAN_ESR_BOFF) SEND("Bus off"); + if(CAN->ESR & CAN_ESR_EPVF) SEND("Passive error limit"); + if(CAN->ESR & CAN_ESR_EWGF) SEND("Error counter limit"); + // 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(0); + } + /* + static uint32_t lastFloodTime = 0; + if(flood_msg && (Tms - lastFloodTime) > (FLOOD_PERIOD_MS-1)){ // flood every ~5ms + lastFloodTime = Tms; + can_send(flood_msg->data, flood_msg->length, flood_msg->ID); + }*/ +} + +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; + }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; + __attribute__((fallthrough)); + case 7: + hb |= (uint32_t)msg[6] << 16; + __attribute__((fallthrough)); + case 6: + hb |= (uint32_t)msg[5] << 8; + __attribute__((fallthrough)); + case 5: + hb |= (uint32_t)msg[4]; + __attribute__((fallthrough)); + case 4: + lb |= (uint32_t)msg[3] << 24; + __attribute__((fallthrough)); + case 3: + lb |= (uint32_t)msg[2] << 16; + __attribute__((fallthrough)); + case 2: + lb |= (uint32_t)msg[1] << 8; + __attribute__((fallthrough)); + 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(){ + uint8_t msg = CMD_TOGGLE; + if(CAN_OK != can_send(&msg, 1, TARG_ID)) SEND("Bus busy!\n"); +} + +void can_send_broadcast(){ + uint8_t msg = CMD_BCAST; + if(CAN_OK != can_send(&msg, 1, BCAST_ID)) SEND("Bus busy!\n"); + MSG("Broadcast message sent\n"); +} + +void set_flood(CAN_message *msg){ + if(!msg) flood_msg = NULL; + else{ + memcpy(&loc_flood_msg, msg, sizeof(CAN_message)); + flood_msg = &loc_flood_msg; + } +}*/ + +static void can_process_fifo(uint8_t fifo_num){ + if(fifo_num > 1) return; + CAN_FIFOMailBox_TypeDef *box = &CAN->sFIFOMailBox[fifo_num]; + volatile uint32_t *RFxR = (fifo_num) ? &CAN->RF1R : &CAN->RF0R; + // 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 + CAN_message msg; + uint8_t *dat = msg.data; + uint8_t len = box->RDTR & 0x0f; + msg.length = len; + msg.ID = box->RIR >> 21; + msg.fifoNum = fifo_num; // @parsing only data from FIFO0 will be accepted, FIFO1 is for monitoring + if(len){ // message can be without data + uint32_t hb = box->RDHR, lb = box->RDLR; + switch(len){ + case 8: + dat[7] = hb>>24; + __attribute__((fallthrough)); + case 7: + dat[6] = (hb>>16) & 0xff; + __attribute__((fallthrough)); + case 6: + dat[5] = (hb>>8) & 0xff; + __attribute__((fallthrough)); + case 5: + dat[4] = hb & 0xff; + __attribute__((fallthrough)); + case 4: + dat[3] = lb>>24; + __attribute__((fallthrough)); + case 3: + dat[2] = (lb>>16) & 0xff; + __attribute__((fallthrough)); + case 2: + dat[1] = (lb>>8) & 0xff; + __attribute__((fallthrough)); + 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 + } + *RFxR = 0; // clear FOVR & FULL +} + +void cec_can_isr(){ + 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; + } + 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; + } +} + +// accept only data for given device @ FIFO0, filter 0 +void can_accept_one(){ + CAN->FMR = CAN_FMR_FINIT; // Enter filter init mode, (16-bit + mask, bank 0 for FIFO 0) + CAN->FA1R = CAN_FA1R_FACT0; // Acivate filter 0 for ID + // main data - FIFO0, filter0 + CAN->FM1R = CAN_FM1R_FBM0; // Identifier list mode + CAN->sFilterRegister[0].FR1 = (CANID << 5) | (0x8f<<16); // Set the Id list + //CAN->sFilterRegister[0].FR2 = (0x8f<<16) | 0x8f; + CAN->FMR &= ~CAN_FMR_FINIT; // Leave filter init +} +// accept everything @ FIFO1, filter 4 +void can_accept_any(){ + CAN->FMR = CAN_FMR_FINIT; + CAN->FA1R |= CAN_FA1R_FACT1; // Acivate bank 1 + CAN->FFA1R = CAN_FFA1R_FFA1; // bank 1 for FIFO1 + CAN->FM1R &= ~CAN_FM1R_FBM1; // MASK + CAN->sFilterRegister[1].FR1 = 0; // all IDs + CAN->sFilterRegister[1].FR2 = (0x8f<<16) | 0x8f; + CAN->FMR &= ~CAN_FMR_FINIT; +} diff --git a/F0-nolib/CANbus_stepper/src/can.h b/F0-nolib/CANbus_stepper/src/can.h new file mode 100644 index 0000000..c5e00c9 --- /dev/null +++ b/F0-nolib/CANbus_stepper/src/can.h @@ -0,0 +1,89 @@ +/* + * geany_encoding=koi8-r + * can.h + * + * Copyright 2018 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ +#pragma once +#ifndef __CAN_H__ +#define __CAN_H__ + +#include "hardware.h" + +// default CAN speed - 100kbps +#define CAN_SPEED_DEFAULT 100 + +// amount of filter banks in STM32F0 +#define STM32F0FBANKNO 28 +// flood period in milliseconds +#define FLOOD_PERIOD_MS 5 + +// simple 1-byte commands +//#define CMD_TOGGLE (0xDA) +//#define CMD_BCAST (0xAD) +// mask clearing bits of board address +#define CAN_ID_MASK (0x7E0) +// prefix to make ID from any number +#define CAN_ID_PREFIX (0x70) +// "target" ID: num=0 +//#define TARG_ID (CAN_ID_PREFIX & CAN_ID_MASK) +// "broadcast" ID: all ones +//#define BCAST_ID (0x7FF) + +// incoming message buffer size +#define CAN_INMESSAGE_SIZE (8) + +// CAN message +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; + +typedef enum{ + CAN_STOP, + CAN_READY, + CAN_BUSY, + CAN_OK, + CAN_FIFO_OVERRUN +} CAN_status; + +extern uint16_t masterID; // ID to send answers by CAN + +CAN_status CAN_get_status(); + +void readCANID(); +uint16_t getCANID(); + +void CAN_reinit(uint16_t speed); +void CAN_setup(uint16_t speed); + +CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id); +//void can_send_dummy(); +//void can_send_broadcast(); +void can_proc(); + +CAN_message *CAN_messagebuf_pop(); +void can_accept_any(); +void can_accept_one(); +//void set_flood(CAN_message *msg); + +#endif // __CAN_H__ diff --git a/F0-nolib/CANbus_stepper/src/can_process.c b/F0-nolib/CANbus_stepper/src/can_process.c new file mode 100644 index 0000000..fbef0f1 --- /dev/null +++ b/F0-nolib/CANbus_stepper/src/can_process.c @@ -0,0 +1,101 @@ +/* + * geany_encoding=koi8-r + * can_process.c + * + * Copyright 2018 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ +#include "adc.h" +#include "can.h" +#include "can_process.h" +#include "proto.h" + +extern volatile uint32_t Tms; // timestamp data + +// v==0 - send V12 & V5 +static void senduival(){ + uint8_t buf[5]; + uint16_t *vals = getUval(); + buf[0] = CMD_GETUVAL; // V12 and V5 + buf[1] = vals[0] >> 8; // H + buf[2] = vals[0] & 0xff;// L + buf[3] = vals[1] >> 8; // -//- + buf[4] = vals[1] & 0xff; + SEND_CAN(buf, 5); +} + +static void sendu16(uint8_t cmd, uint16_t data){ + uint8_t buf[3]; + buf[0] = cmd; + buf[1] = data >> 8; + buf[2] = data & 0xff; + SEND_CAN(buf, 3); +} + +void can_messages_proc(){ + CAN_message *can_mesg = CAN_messagebuf_pop(); + if(!can_mesg) return; // no data in buffer + uint8_t len = can_mesg->length; +#ifndef EBUG + if(can_mesg->fifoNum == 1){ // not my data - just show it +#endif + if(monitCAN){ + printu(Tms); + SEND(" #"); + printuhex(can_mesg->ID); + SEND(" (F#"); printu(can_mesg->fifoNum); SEND(")"); + for(uint8_t ctr = 0; ctr < len; ++ctr){ + SEND(" "); + printuhex(can_mesg->data[ctr]); + } + IWDG->KR = IWDG_REFRESH; + newline(); sendbuf(); + } +#ifndef EBUG + return; + } +#endif + IWDG->KR = IWDG_REFRESH; + if(!len) return; // no data in message + uint8_t *data = can_mesg->data; + switch(data[0]){ + case CMD_PING: // pong + SEND_CAN(data, 1); + break; + case CMD_GETMCUTEMP: + sendu16(CMD_GETMCUTEMP, (int16_t)getMCUtemp()); + break; + case CMD_GETUVAL: + senduival(); + break; + case CMD_GETU3V3: + sendu16(CMD_GETU3V3, (uint16_t)getVdd()); + break; + } +} + +// try to send messages, wait no more than 100ms +CAN_status try2send(uint8_t *buf, uint8_t len, uint16_t id){ + uint32_t Tstart = Tms; + while(Tms - Tstart < SEND_TIMEOUT_MS){ + if(CAN_OK == can_send(buf, len, id)) return CAN_OK; + IWDG->KR = IWDG_REFRESH; + } + SEND("CAN_BUSY\n"); + return CAN_BUSY; +} diff --git a/F0-nolib/CANbus_stepper/src/can_process.h b/F0-nolib/CANbus_stepper/src/can_process.h new file mode 100644 index 0000000..8cee33a --- /dev/null +++ b/F0-nolib/CANbus_stepper/src/can_process.h @@ -0,0 +1,38 @@ +/* + * geany_encoding=koi8-r + * can_process.h + * + * Copyright 2018 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ +#include "can.h" + +// timeout for trying to send data +#define SEND_TIMEOUT_MS (10) + +// 8-bit commands sent by master +typedef enum{ + CMD_PING, // just echo it back + CMD_GETMCUTEMP, // MCU temperature value + CMD_GETUVAL, // answer with values of V12 and V5 + CMD_GETU3V3, // answer with values of V3.3 +} CAN_commands; + +void can_messages_proc(); +#define SEND_CAN(a,b) try2send(a, b, masterID) +CAN_status try2send(uint8_t *buf, uint8_t len, uint16_t id); diff --git a/F0-nolib/CANbus_stepper/src/canstepper.bin b/F0-nolib/CANbus_stepper/src/canstepper.bin old mode 100644 new mode 100755 index f5d089148ddca1d561deb60b6dbf961512099451..2233ef357832b247420849e20c648d9a780bf735 GIT binary patch literal 13776 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 SVh{&F%HSGFeok|G^1lFvfVT_) delta 4981 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 ZOW^cN|GhL+;KRTYNU{j + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +/** + ATTENTION!! + This things works only if you will add next section: + + .myvars : + { + . = ALIGN(1024); + __varsstart = ABSOLUTE(.); + KEEP(*(.myvars)); + } > rom + + after section .data +*/ +#include +#include "adc.h" +#include "flash.h" +#include "proto.h" // printout +#include "steppers.h" +#include // memcpy + +// max amount of Config records stored (will be recalculate in flashstorage_init() +static uint32_t maxCnum = FLASH_BLOCK_SIZE / sizeof(user_conf); + +#define USERCONF_INITIALIZER { \ + .userconf_sz = sizeof(user_conf) \ + ,.defflags = 0 \ + ,.CANspeed = 100 \ + ,.driver_type = DRV_NONE \ + } + +static int erase_flash(const void*, const void*); +static int write2flash(const void*, const void*, uint32_t); +// don't write `static` here, or get error: +// 'memcpy' forming offset 8 is out of the bounds [0, 4] of object '__varsstart' with type 'uint32_t' +const user_conf *Flash_Data = (const user_conf *)(&__varsstart); + +user_conf the_conf = USERCONF_INITIALIZER; + +static int currentconfidx = -1; // index of current configuration + +/** + * @brief binarySearch - binary search in flash for last non-empty cell + * any struct searched should have its sizeof() @ the first field!!! + * @param l - left index + * @param r - right index (should be @1 less than last index!) + * @param start - starting address + * @param stor_size - size of structure to search + * @return index of non-empty cell or -1 + */ +static int binarySearch(int r, const uint8_t *start, int stor_size){ + int l = 0; + while(r >= l){ + int mid = l + (r - l) / 2; + const uint8_t *s = start + mid * stor_size; + if(*((const uint16_t*)s) == stor_size){ + if(*((const uint16_t*)(s + stor_size)) == 0xffff){ // next is free + return mid; + }else{ // element is to the right + l = mid + 1; + } + }else{ // element is to the left + r = mid - 1; + } + } + return -1; // not found +} + +/** + * @brief flashstorage_init - initialization of user conf storage + * run in once @ start + */ +void flashstorage_init(){ + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + uint32_t flsz = FLASH_SIZE * 1024; // size in bytes + flsz -= (uint32_t)(&__varsstart) - FLASH_BASE; + maxCnum = flsz / sizeof(user_conf); +//SEND("flsz="); printu(flsz); +//SEND("\nmaxCnum="); printu(maxCnum); newline(); sendbuf(); + } + // -1 if there's no data at all & flash is clear; maxnum-1 if flash is full + currentconfidx = binarySearch((int)maxCnum-2, (const uint8_t*)Flash_Data, sizeof(user_conf)); + if(currentconfidx > -1){ + memcpy(&the_conf, &Flash_Data[currentconfidx], sizeof(user_conf)); + } +} + +// store new configuration +// @return 0 if all OK +int store_userconf(){ + // maxnum - 3 means that there always should be at least one empty record after last data + // for binarySearch() checking that there's nothing more after it! + if(currentconfidx > (int)maxCnum - 3){ // there's no more place + currentconfidx = 0; + if(erase_flash(Flash_Data, (&__varsstart))) return 1; + }else ++currentconfidx; // take next data position (0 - within first run after firmware flashing) + return write2flash((const void*)&Flash_Data[currentconfidx], &the_conf, sizeof(the_conf)); +} + +static int write2flash(const void *start, const void *wrdata, uint32_t stor_size){ + int ret = 0; + if (FLASH->CR & FLASH_CR_LOCK){ // unloch flash + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; + } + while (FLASH->SR & FLASH_SR_BSY); + if(FLASH->SR & FLASH_SR_WRPRTERR){ + MSG("Can't remove write protection\n"); + return 1; // write protection + } + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; // clear all flags + FLASH->CR |= FLASH_CR_PG; + const uint16_t *data = (const uint16_t*) wrdata; + volatile uint16_t *address = (volatile uint16_t*) start; + uint32_t i, count = (stor_size + 1) / 2; + for (i = 0; i < count; ++i){ + IWDG->KR = IWDG_REFRESH; + *(volatile uint16_t*)(address + i) = data[i]; + while (FLASH->SR & FLASH_SR_BSY); + if(FLASH->SR & FLASH_SR_PGERR){ + ret = 1; // program error - meet not 0xffff + MSG("FLASH_SR_PGERR\n"); + break; + }else while (!(FLASH->SR & FLASH_SR_EOP)); + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; + } + FLASH->CR |= FLASH_CR_LOCK; // lock it back + FLASH->CR &= ~(FLASH_CR_PG); + MSG("Flash stored\n"); + return ret; +} + +/** + * @brief erase_flash - erase N pages of flash memory + * @param start - first address + * @param end - last address (or NULL if need to erase all flash remaining) + * @return 0 if succeed + */ +static int erase_flash(const void *start, const void *end){ + int ret = 0; + uint32_t nblocks = 1, flsz = 0; + if(!end){ // erase all remaining + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + flsz = FLASH_SIZE * 1024; // size in bytes + flsz -= (uint32_t)start - FLASH_BASE; + } + }else{ // erase a part + flsz = (uint32_t)end - (uint32_t)start; + } + nblocks = flsz / FLASH_BLOCK_SIZE; + if(nblocks == 0 || nblocks >= FLASH_SIZE) return 1; + for(uint32_t i = 0; i < nblocks; ++i){ +#ifdef EBUG + SEND("Try to erase page #"); printu(i); newline(); sendbuf(); +#endif + IWDG->KR = IWDG_REFRESH; + /* (1) Wait till no operation is on going */ + /* (2) Clear error & EOP bits */ + /* (3) Check that the Flash is unlocked */ + /* (4) Perform unlock sequence */ + while ((FLASH->SR & FLASH_SR_BSY) != 0){} /* (1) */ + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; /* (2) */ + /* if (FLASH->SR & FLASH_SR_EOP){ + FLASH->SR |= FLASH_SR_EOP; + }*/ + if ((FLASH->CR & FLASH_CR_LOCK) != 0){ /* (3) */ + FLASH->KEYR = FLASH_KEY1; /* (4) */ + FLASH->KEYR = FLASH_KEY2; + } + /* (1) Set the PER bit in the FLASH_CR register to enable page erasing */ + /* (2) Program the FLASH_AR register to select a page to erase */ + /* (3) Set the STRT bit in the FLASH_CR register to start the erasing */ + /* (4) Wait until the EOP flag in the FLASH_SR register set */ + /* (5) Clear EOP flag by software by writing EOP at 1 */ + /* (6) Reset the PER Bit to disable the page erase */ + FLASH->CR |= FLASH_CR_PER; /* (1) */ + FLASH->AR = (uint32_t)Flash_Data + i*FLASH_BLOCK_SIZE; /* (2) */ + FLASH->CR |= FLASH_CR_STRT; /* (3) */ + while(!(FLASH->SR & FLASH_SR_EOP)); + FLASH->SR |= FLASH_SR_EOP; /* (5)*/ + if(FLASH->SR & FLASH_SR_WRPRTERR){ /* Check Write protection error */ + ret = 1; + MSG("Write protection error!\n"); + FLASH->SR |= FLASH_SR_WRPRTERR; /* Clear the flag by software by writing it at 1*/ + break; + } + FLASH->CR &= ~FLASH_CR_PER; /* (6) */ + } + return ret; +} + +void dump_userconf(){ + SEND("userconf_addr="); printuhex((uint32_t)Flash_Data); + SEND("\nuserconf_sz="); printu(the_conf.userconf_sz); + SEND("\nflags="); printuhex(the_conf.defflags); + SEND("\nCANspeed="); printu(the_conf.CANspeed); + SEND("\ndriver_type="); + const char *p = "NONE"; + switch(the_conf.driver_type){ + case DRV_2130: + p = "TMC2130"; + break; + case DRV_4988: + p = "A4988"; + break; + case DRV_8825: + p = "DRV8825"; + break; + } + SEND(p); + newline(); + sendbuf(); +} diff --git a/F0-nolib/CANbus_stepper/src/flash.h b/F0-nolib/CANbus_stepper/src/flash.h new file mode 100644 index 0000000..4e57c5c --- /dev/null +++ b/F0-nolib/CANbus_stepper/src/flash.h @@ -0,0 +1,51 @@ +/* + * flash.h + * + * Copyright 2017 Edward V. Emelianov + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + * + */ + +#pragma once +#ifndef __FLASH_H__ +#define __FLASH_H__ + +#include "hardware.h" + +#define FLASH_BLOCK_SIZE (1024) +#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7CC) +#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG) + +/* + * struct to save user configurations + */ +typedef struct __attribute__((packed, aligned(4))){ + uint16_t userconf_sz; // "magick number" + uint16_t CANspeed; // default CAN speed + uint8_t defflags; // default flags + uint8_t driver_type; // user's settings: type of stepper's driver +} user_conf; + +extern user_conf the_conf; // global user config (read from FLASH to RAM) +// data from ld-file: start address of storage +extern const uint32_t __varsstart; + +void flashstorage_init(); +int store_userconf(); +void dump_userconf(); + +#endif // __FLASH_H__ diff --git a/F0-nolib/CANbus_stepper/src/hardware.c b/F0-nolib/CANbus_stepper/src/hardware.c index 96b6cf2..ed7a0ac 100644 --- a/F0-nolib/CANbus_stepper/src/hardware.c +++ b/F0-nolib/CANbus_stepper/src/hardware.c @@ -1,12 +1,10 @@ /* - * geany_encoding=koi8-r - * hardware.c - hardware-dependent macros & functions + * This file is part of the Stepper project. + * Copyright 2020 Edward V. Emelianov . * - * Copyright 2018 Edward V. Emelianov - * - * This program is free software; you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -15,10 +13,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * + * along with this program. If not, see . */ #include "hardware.h" @@ -73,14 +68,44 @@ void iwdg_setup(){ IWDG->KR = IWDG_REFRESH; /* (6) */ } -void gpio_setup(void){ +/* +MODER - input/output/alternate/analog +OTYPER - pushpull/opendrain +OSPEEDR - low(x0)/med(01)/high(11) +PUPDR - no/pullup/pulldown/reserved +AFRL, AFRH - alternate fno +*/ +void gpio_setup(){ // here we turn on clocking for all GPIO used RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_GPIOFEN | RCC_AHBENR_DMAEN; + // setup pins need @start: Vio_ON (PF0, opendrain), ~FAULT (PF1, floating IN), + // ~SLEEP (PC15, pushpull), DIR (PA4, pushpull), ~EN (PC13, pushpull) + // ~CS, microstepping2, (PC14, pushpull // PA8 - Tx/Rx - GPIOA->MODER = GPIO_MODER_MODER8_O; - // PB12..15 - board address, pullup input - GPIOB->PUPDR = GPIO_PUPDR_PUPDR12_0 | GPIO_PUPDR_PUPDR13_0 | GPIO_PUPDR_PUPDR14_0 | GPIO_PUPDR_PUPDR15_0; + // PB12..15 - board address, pullup input; PB0..2, PB10 - ESW, pullup inputs (inverse) + VIO_OFF(); + SLEEP_ON(); + DRV_DISABLE(); + // PA. PP: PA4, PA8; AIN: PA0, PA1 + GPIOA->MODER = GPIO_MODER_MODER8_O | GPIO_MODER_MODER4_O | GPIO_MODER_MODER1_AI | GPIO_MODER_MODER0_AI; + GPIOA->PUPDR = 0; + GPIOA->OTYPER = 0; + // PB. PUin: 0,1,2,10,12,13,14,15 + GPIOB->MODER = 0; + GPIOB->PUPDR = GPIO_PUPDR0_PU | GPIO_PUPDR1_PU | GPIO_PUPDR2_PU | GPIO_PUPDR10_PU | + GPIO_PUPDR12_PU | GPIO_PUPDR13_PU | GPIO_PUPDR14_PU | GPIO_PUPDR15_PU; + GPIOB->OTYPER = 0; + // PC. PP: 13..15 + GPIOC->MODER = GPIO_MODER_MODER13_O | GPIO_MODER_MODER14_O | GPIO_MODER_MODER15_O; + GPIOC->PUPDR = 0; + GPIOC->OTYPER = 0; + // PF. OD: 0; FLin: 1 + GPIOF->MODER = GPIO_MODER_MODER0_O; + //GPIOF->PUPDR = GPIO_PUPDR1_PU; + GPIOF->PUPDR = 0; + GPIOF->OTYPER = 0; + // other pins will be set up later /* // Set LEDS (PC13/14) as output GPIOC->MODER = (GPIOC->MODER & ~(GPIO_MODER_MODER13 | GPIO_MODER_MODER14) @@ -94,3 +119,8 @@ uint8_t refreshBRDaddr(){ return (brdADDR = READ_BRD_ADDR()); } uint8_t getBRDaddr(){return brdADDR;} + +void sleep(uint16_t ms){ + uint32_t Tnew = Tms + ms; + while(Tnew != Tms) nop(); +} diff --git a/F0-nolib/CANbus_stepper/src/hardware.h b/F0-nolib/CANbus_stepper/src/hardware.h index e125630..2c87c39 100644 --- a/F0-nolib/CANbus_stepper/src/hardware.h +++ b/F0-nolib/CANbus_stepper/src/hardware.h @@ -1,12 +1,10 @@ /* - * geany_encoding=koi8-r - * hardware.h + * This file is part of the Stepper project. + * Copyright 2020 Edward V. Emelianov . * - * Copyright 2018 Edward V. Emelianov - * - * This program is free software; you can redistribute it and/or modify + * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, @@ -15,11 +13,9 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - * + * along with this program. If not, see . */ + #pragma once #ifndef __HARDWARE_H__ #define __HARDWARE_H__ @@ -43,12 +39,49 @@ #define RS485_TX() do{GPIOA->BSRR = GPIO_BSRR_BS_8;}while(0) #define RS485_RX() do{GPIOA->BRR = GPIO_BRR_BR_8;}while(0) +// pins manipulation +// DIR - PA4 +#define SET_DIR() do{GPIOA->BSRR = 1<<4;}while(0) +#define CLEAR_DIR() do{GPIOA->BRR = 1<<4;}while(0) +// read ~FAULT - PF1 (inverse) +#define FAULT_STATE() ((GPIOF->IDR & (1<<1)) ? 0 : 1) +// ~SLEEP - PC15 (inverse) +#define SLEEP_ON() do{GPIOC->BRR = 1<<15;}while(0) +#define SLEEP_OFF() do{GPIOC->BSRR = 1<<15;}while(0) +// configure ~SLP as PP output +#define SLP_CFG_OUT() do{GPIOC->MODER = (GPIOC->MODER&~GPIO_MODER_MODER15) | GPIO_MODER_MODER15_O; }while(0) +// and ~SLP as floating input +#define SLP_CFG_IN() do{GPIOC->MODER = (GPIOC->MODER&~GPIO_MODER_MODER15);}while(0) +// SLP state when input (non-inverted) +#define SLP_STATE() ((GPIOC->IDR & (1<<15)) ? 1 : 0) +// ~EN, CFG6 - PC13 (inverse) +#define DRV_ENABLE() do{GPIOC->BRR = 1<<13;}while(0) +#define DRV_DISABLE() do{GPIOC->BSRR = 1<<13;}while(0) +// configure ~EN as PP output +#define EN_CFG_OUT() do{GPIOC->MODER = (GPIOC->MODER&~GPIO_MODER_MODER13) | GPIO_MODER_MODER13_O; }while(0) +// configure ~EN as floating input +#define EN_CFG_IN() do{GPIOC->MODER = (GPIOC->MODER&~GPIO_MODER_MODER13);}while(0) +// EN state when it's an input (non-inverted) +#define EN_STATE() ((GPIOC->IDR & (1<<13)) ? 1 : 0) +// ~CS, CFG3, microstepping2 - PC14 +#define SET_UST2() do{GPIOC->BSRR = 1<<14;}while(0) +#define RESET_UST2() do{GPIOC->BRR = 1<<14;}while(0) +#define CS_ACTIVE() do{GPIOC->BRR = 1<<14;}while(0) +#define CS_PASSIVE() do{GPIOC->BSRR = 1<<14;}while(0) +// configure ~CS as PP output +//#define CS_CFG_OUT() do{GPIOC->MODER = (GPIOC->MODER&~GPIO_MODER_MODER14) | GPIO_MODER_MODER14_O; }while(0) +// ~CS as floating input +; +// Vio_ON, PF0 (inverse) +#define VIO_ON() do{GPIOF->BRR = 1;}while(0) +#define VIO_OFF() do{GPIOF->BSRR = 1;}while(0) + extern volatile uint32_t Tms; void Jump2Boot(); -void gpio_setup(void); +void gpio_setup(); void iwdg_setup(); uint8_t getBRDaddr(); uint8_t refreshBRDaddr(); - +void sleep(uint16_t ms); #endif // __HARDWARE_H__ diff --git a/F0-nolib/CANbus_stepper/src/main.c b/F0-nolib/CANbus_stepper/src/main.c index 098e9d5..fe31317 100644 --- a/F0-nolib/CANbus_stepper/src/main.c +++ b/F0-nolib/CANbus_stepper/src/main.c @@ -19,6 +19,9 @@ * MA 02110-1301, USA. */ #include "adc.h" +#include "can.h" +#include "can_process.h" +#include "flash.h" #include "hardware.h" #include "proto.h" #include "usart.h" @@ -44,14 +47,48 @@ void clstate_handler(uint16_t val){ usart_putchar('\n'); }*/ +#define USBBUF 63 +// usb getline +static char *get_USB(){ + static char tmpbuf[USBBUF+1], *curptr = tmpbuf; + static int rest = USBBUF; + uint8_t x = USB_receive((uint8_t*)curptr); + if(!x) return NULL; + curptr[x] = 0; + if(x == 1 && *curptr == 0x7f){ // backspace + if(curptr > tmpbuf){ + --curptr; + USND("\b \b"); + } + return NULL; + } + USB_sendstr(curptr); // echo + if(curptr[x-1] == '\n'){ + curptr = tmpbuf; + rest = USBBUF; + // omit empty lines + if(tmpbuf[0] == '\n') return NULL; + // and wrong empty lines + if(tmpbuf[0] == '\r' && tmpbuf[1] == '\n') return NULL; + return tmpbuf; + } + curptr += x; rest -= x; + if(rest <= 0){ // buffer overflow + curptr = tmpbuf; + rest = USBBUF; + } + return NULL; +} + int main(void){ uint32_t lastT = 0; - char tmpbuf[129]; sysreset(); SysTick_Config(6000, 1); - gpio_setup(); + gpio_setup(); // + read board address usart_setup(); adc_setup(); + flashstorage_init(); + /* if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured usart_send_blocking("WDGRESET=1\n", 11); } @@ -59,35 +96,30 @@ int main(void){ usart_send_blocking("SOFTRESET=1\n", 12); } RCC->CSR |= RCC_CSR_RMVF; // remove reset flags + */ + CAN_setup(the_conf.CANspeed); USB_setup(); - //iwdg_setup(); + iwdg_setup(); while (1){ IWDG->KR = IWDG_REFRESH; // refresh watchdog - if(lastT > Tms || Tms - lastT > 499){ + if(Tms - lastT > 499){ lastT = Tms; } + can_proc(); usb_proc(); usart_proc(); // switch RS-485 to Rx after last byte sent - uint8_t r = 0; - if((r = USB_receive(tmpbuf, 128))){ - tmpbuf[r] = 0; - cmd_parser(tmpbuf, TARGET_USB); + char *txt; + if((txt = get_USB())){ + cmd_parser(txt, TARGET_USB); } + IWDG->KR = IWDG_REFRESH; if(usartrx()){ // usart1 received data, store in in buffer - char *txt = NULL; - r = usart_getline(&txt); -/* -buftgt(TARGET_USB); -addtobuf("got "); -printu(r); -addtobuf(" bytes over USART:\n"); -addtobuf(txt); -addtobuf("\n====\n"); -sendbuf(); -*/ + usart_getline(&txt); cmd_parser(txt, TARGET_USART); } + IWDG->KR = IWDG_REFRESH; + can_messages_proc(); } return 0; } diff --git a/F0-nolib/CANbus_stepper/src/proto.c b/F0-nolib/CANbus_stepper/src/proto.c index aafe933..a0a3340 100644 --- a/F0-nolib/CANbus_stepper/src/proto.c +++ b/F0-nolib/CANbus_stepper/src/proto.c @@ -21,20 +21,31 @@ * */ #include "adc.h" +#include "can.h" +#include "flash.h" #include "hardware.h" #include "proto.h" +#include "steppers.h" #include "usart.h" #include "usb.h" #include // strlen, strcpy( extern volatile uint8_t canerror; - +uint8_t monitCAN = 0; // ==1 to show CAN messages #define BUFSZ UARTBUFSZ static char buff[BUFSZ+1], *bptr = buff; static uint8_t blen = 0, // length of data in `buff` USBcmd = 0; // ==1 if buffer prepared for USB +char *omit_spaces(char *buf){ + while(*buf){ + if(*buf > ' ') break; + ++buf; + } + return buf; +} + void buftgt(uint8_t isUSB){ USBcmd = isUSB; } @@ -44,7 +55,7 @@ void sendbuf(){ if(blen == 0) return; if(USBcmd){ *bptr = 0; - USB_send(buff); + USB_sendstr(buff); }else while(LINE_BUSY == usart_send(buff, blen)){IWDG->KR = IWDG_REFRESH;} bptr = buff; blen = 0; @@ -55,7 +66,7 @@ void addtobuf(const char *txt){ int l = strlen(txt); if(l > BUFSZ){ sendbuf(); - if(USBcmd) USB_send(txt); + if(USBcmd) USB_sendstr(txt); else usart_send_blocking(txt, l); }else{ if(blen+l > BUFSZ){ @@ -105,19 +116,161 @@ static inline void showUIvals(){ newline(); } -// check address & return 0 if wrong or address to roll to next non-digit -static int chk485addr(const char *txt){ - int32_t N; - int p = getnum(txt, &N); - if(!p){ - USB_send("Not num\n"); - return 0; - } +// check address & return 0 if wrong or roll to next non-digit +static char *chk485addr(char *txt){ + uint32_t N; + char *nxt = getnum(txt, &N); + if(nxt == txt) return NULL; if(N == getBRDaddr()){ - return p; + return nxt; + } + return NULL; +} + +// parse `txt` to CAN_message +static CAN_message *parseCANmsg(char *txt){ + static CAN_message canmsg; + uint32_t N; + char *n; + int ctr = -1; + canmsg.ID = 0xffff; + do{ + txt = omit_spaces(txt); + n = getnum(txt, &N); + if(txt == n) break; + txt = n; + if(ctr == -1){ + if(N > 0x7ff){ + SEND("ID should be 11-bit number!\n"); + return NULL; + } + canmsg.ID = (uint16_t)(N&0x7ff); + ctr = 0; + continue; + } + if(ctr > 7){ + SEND("ONLY 8 data bytes allowed!\n"); + return NULL; + } + if(N > 0xff){ + SEND("Every data portion is a byte!\n"); + return NULL; + } + canmsg.data[ctr++] = (uint8_t)(N&0xff); + }while(1); + if(canmsg.ID == 0xffff){ + SEND("NO ID given, send nothing!\n"); + return NULL; + } + canmsg.length = (uint8_t) ctr; + return &canmsg; +} + +// send command, format: ID (hex/bin/dec) data bytes (up to 8 bytes, space-delimeted) +TRUE_INLINE void sendCANcommand(char *txt){ + CAN_message *msg = parseCANmsg(txt); + if(!msg) return; + uint32_t N = 1000000; + while(CAN_BUSY == can_send(msg->data, msg->length, msg->ID)){ + if(--N == 0) break; + } +} + +static uint8_t userconf_changed = 0; // ==1 if user_conf was changed +TRUE_INLINE void userconf_manip(char *txt){ + txt = omit_spaces(txt); + switch(*txt){ + case 'd': // dump + dump_userconf(); + break; + case 's': // store + if(userconf_changed){ + if(!store_userconf()){ + userconf_changed = 0; + SEND("Stored!"); + }else SEND("Error when storing!"); + } + break; + default: + SEND("Wrong argument of userconf manipulation: "); + SEND(txt); + } +} + +// a set of setters for user_conf +TRUE_INLINE void setters(char *txt){ + uint32_t U; + txt = omit_spaces(txt); + if(!*txt){ + SEND("Setters need more arguments"); + return; + } + char *nxt = getnum(txt + 1, &U); + switch(*txt){ + case 'c': // set CAN speed + if(nxt == txt + 1){ + SEND("No CAN speed given"); + return; + } + if(U < 50){ + SEND("Speed should be not less than 50kbps"); + return; + } + if(U > 3000){ + SEND("Speed should be not greater than 3000kbps"); + return; + } + if(the_conf.CANspeed != (uint16_t)U){ + the_conf.CANspeed = (uint16_t)U; + userconf_changed = 1; + } + break; + default: + SEND("Wrong argument of setters: "); + SEND(txt); + } +} + +TRUE_INLINE void driver_commands(char *txt){ + uint32_t U; + char *nxt; + const char *drvshould = "Driver type should be one of: 2130, 4988, 8825"; + txt = omit_spaces(txt); + if(!*txt){ + SEND("Driver commands need more arguments"); + return; + } + switch(*txt){ + case 'i': // init + initDriver(); + break; + case 's': // set type + nxt = getnum(txt + 1, &U); + if(nxt == txt+1){ + SEND(drvshould); + break; + } + switch(U){ + case 2130: + the_conf.driver_type = DRV_2130; + SEND("TMC2130"); + break; + case 4988: + the_conf.driver_type = DRV_4988; + SEND("A4988"); + break; + case 8825: + the_conf.driver_type = DRV_8825; + SEND("DRV8825"); + break; + default: + SEND(drvshould); + } + break; + default: + SEND("Wrong argument of driver commands: "); + SEND(txt); } - USB_send("Not me\n"); - return 0; } /** @@ -125,36 +278,60 @@ static int chk485addr(const char *txt){ * @param txt - buffer with commands & data * @param isUSB - == 1 if data got from USB */ -void cmd_parser(const char *txt, uint8_t isUSB){ +void cmd_parser(char *txt, uint8_t isUSB){ sendbuf(); USBcmd = isUSB; - int p = 0; // we can't simple use &txt[p] as variable: it can be non-aligned by 4!!! if(isUSB == TARGET_USART){ // check address and roll message to nearest non-space - p = chk485addr(txt); - if(!p) return; + txt = chk485addr(txt); + if(!txt) return; } - // roll to non-space - char c; - while((c = txt[p])){ - if(c == ' ' || c == '\t') ++p; - else break; + txt = omit_spaces(txt); + // long commands, commands with arguments + switch(*txt){ + case 'D': + driver_commands(txt + 1); + goto eof; + break; + case 's': + sendCANcommand(txt + 1); + goto eof; + break; + case 'S': // setters + setters(txt + 1); + goto eof; + break; + case 'U': + userconf_manip(txt + 1); + goto eof; + break; } - //int16_t L = strlen(txt); - char _1st = txt[p]; - switch(_1st){ + if(txt[1] != '\n') *txt = '?'; // help for wrong message length + switch(*txt){ + case '0': + can_accept_one(); + SEND("Accept only my ID @CAN"); + break; + case '@': + can_accept_any(); + SEND("Accept any ID @CAN"); + break; case 'a': showADCvals(); break; - case 'D': + case 'b': SEND("Jump to bootloader.\n"); sendbuf(); Jump2Boot(); break; + case 'd': + dump_userconf(); + break; case 'g': SEND("Board address: "); printuhex(refreshBRDaddr()); - newline(); + SEND("\nCAN IN address (OUT=IN+1): "); + printuhex(getCANID()); break; case 'j': printmcut(); @@ -162,22 +339,47 @@ void cmd_parser(const char *txt, uint8_t isUSB){ case 'k': showUIvals(); break; + case 'm': + monitCAN = !monitCAN; + SEND("CAN monitoring "); + if(monitCAN) SEND("ON"); + else SEND("OFF"); + break; case 't': if(ALL_OK != usart_send("TEST test\n", 10)) - addtobuf("Can't send data over RS485\n"); - else addtobuf("Sent\n"); + SEND("Can't send data over RS485"); + else SEND("Sent"); + break; + case 'T': + SEND("Tms="); printu(Tms); + break; + case 'z': + flashstorage_init(); break; default: // help SEND( + "0 - accept only data for this device\n" + "@ - accept any IDs\n" "a - get raw ADC values\n" - "D - switch to bootloader\n" + "b - switch to bootloader\n" + "d - dump userconf\n" + "Di - init stepper driver (8825, 4988, 2130)\n" + "Ds - set driver type\n" "g - get board address\n" "j - get MCU temperature\n" "k - get U values\n" + "m - start/stop monitoring CAN bus\n" + "s - send data over CAN: s ID [byte0..7]\n" "t - send test sequence over RS-485\n" + "T - print current time\n" + "Sc - set default CAN speed\n" + "Ud - userconf dump\n" + "Us - userconf store\n" ); break; } +eof: + newline(); sendbuf(); } @@ -200,7 +402,7 @@ void printu(uint32_t val){ void printuhex(uint32_t val){ addtobuf("0x"); uint8_t *ptr = (uint8_t*)&val + 3; - int i, j; + int8_t i, j; for(i = 0; i < 4; ++i, --ptr){ for(j = 1; j > -1; --j){ uint8_t half = (*ptr >> (4*j)) & 0x0f; @@ -210,52 +412,73 @@ void printuhex(uint32_t val){ } } -/** - * @brief getnum - read number from string omiting leading spaces - * @param buf (i) - string to process - * @param N (o) - number read (or NULL for test) - * @return amount of symbols processed (or 0 if none) - */ -int getnum(const char *buf, int32_t *N){ - char c; - int positive = -1, srd = 0; - int32_t val = 0; - while((c = *buf++)){ - if(c == '\t' || c == ' '){ - if(positive < 0){ - ++srd; - continue; // beginning spaces - } - else break; // spaces after number +// 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; } - if(c == '-'){ - if(positive < 0){ - ++srd; - positive = 0; - continue; - }else break; // there already was `-` or number - } - if(c < '0' || c > '9') break; - ++srd; - if(positive < 0) positive = 1; - val = val * 10 + (int32_t)(c - '0'); + num *= 10; + num += c - '0'; + ++buf; } - if(positive != -1){ - if(positive == 0){ - if(val == 0) return 0; // single '-' or -0000 - val = -val; - } - if(N) *N = val; - }else return 0; -uint8_t uold = USBcmd; -USBcmd = TARGET_USB; -addtobuf("Got num: "); -if(val < 0){bufputchar('-'); val = -val;} -printu(val); -addtobuf(", N="); -printu(srd); -newline(); -sendbuf(); -USBcmd = uold; - return srd; + *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){ + txt = omit_spaces(txt); + 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/CANbus_stepper/src/proto.h b/F0-nolib/CANbus_stepper/src/proto.h index 2dfbcb6..e3a78f0 100644 --- a/F0-nolib/CANbus_stepper/src/proto.h +++ b/F0-nolib/CANbus_stepper/src/proto.h @@ -37,13 +37,17 @@ #define newline() do{bufputchar('\n');}while(0) -void cmd_parser(const char *buf, uint8_t isUSB); +extern uint8_t monitCAN; + +char *omit_spaces(char *buf); + +void cmd_parser(char *buf, uint8_t isUSB); void addtobuf(const char *txt); void bufputchar(char ch); void sendbuf(); void printu(uint32_t val); void printuhex(uint32_t val); -int getnum(const char *buf, int32_t *N); +char *getnum(char *txt, uint32_t *N); #define TARGET_USB 1 #define TARGET_USART 0 diff --git a/F0-nolib/CANbus_stepper/src/steppers.c b/F0-nolib/CANbus_stepper/src/steppers.c new file mode 100644 index 0000000..0a5c1fb --- /dev/null +++ b/F0-nolib/CANbus_stepper/src/steppers.c @@ -0,0 +1,104 @@ +/* + * This file is part of the Stepper project. + * Copyright 2020 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include "flash.h" +#include "hardware.h" +#include "proto.h" +#include "steppers.h" + +static drv_type driver = DRV_NONE; + +/** + * @brief checkDrv - test if driver connected + */ +static void checkDrv(){ + uint8_t oldstate; + // turn power on and wait a little + SLEEP_ON(); // sleep -> 0 + DRV_DISABLE(); + VIO_ON(); sleep(15); + // check Vdd + if(FAULT_STATE()){ + MSG("No power @ Vin, mailfunction\n"); + driver = DRV_MAILF; + VIO_OFF(); + goto ret; + } + SLP_CFG_IN(); + sleep(2); + // Check is ~SLEEP is in air + oldstate = SLP_STATE(); + if(oldstate) MSG("SLP=1\n"); else MSG("SLP=0\n"); + SLEEP_OFF(); SLP_CFG_OUT(); // sleep -> 1 + sleep(2); + SLP_CFG_IN(); + sleep(2); + if(SLP_STATE()) MSG("SLP=1\n"); else MSG("SLP=0\n"); + if(SLP_STATE() != oldstate){ + MSG("~SLP is in air\n"); + if(driver != DRV_2130){ + driver = DRV_NONE; + VIO_OFF(); + } + goto ret; + } + SLEEP_ON(); SLP_CFG_OUT(); + // check if ~EN is in air + DRV_ENABLE(); // EN->0 + sleep(2); + EN_CFG_IN(); + sleep(2); + oldstate = EN_STATE(); + if(oldstate) MSG("EN=1\n"); else MSG("EN=0\n"); + DRV_DISABLE(); // EN->1 + EN_CFG_OUT(); + sleep(2); + EN_CFG_IN(); + sleep(2); + if(EN_STATE()) MSG("EN=1\n"); else MSG("EN=0\n"); + if(oldstate != EN_STATE()){ + MSG("~EN is in air\n"); + driver = DRV_NONE; + VIO_OFF(); + goto ret; + } +ret: + DRV_DISABLE(); + EN_CFG_OUT(); // return OUT conf + SLEEP_OFF(); + SLP_CFG_OUT(); +#ifdef EBUG + sendbuf(); +#endif +} + +/** + * @brief initDriver - try to init driver + * @return driver type + */ +drv_type initDriver(){ + if(driver != DRV_NOTINIT){ // reset all settings + MSG("clear GPIO & other setup\n"); + // TODO: turn off SPI & timer + gpio_setup(); // reset pins control + } + driver = the_conf.driver_type; + checkDrv(); + if(driver == DRV_NONE) return driver; + // TODO: some stuff here + return driver; +} diff --git a/F0-nolib/CANbus_stepper/src/steppers.h b/F0-nolib/CANbus_stepper/src/steppers.h new file mode 100644 index 0000000..7fcfb08 --- /dev/null +++ b/F0-nolib/CANbus_stepper/src/steppers.h @@ -0,0 +1,36 @@ +/* + * This file is part of the Stepper project. + * Copyright 2020 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#ifndef STEPPERS_H__ +#define STEPPERS_H__ + +#include + +typedef enum{ + DRV_NONE, // driver is absent + DRV_NOTINIT,// not initialized + DRV_MAILF, // mailfunction - no Vdd when Vio_ON activated + DRV_8825, // DRV8825 connected + DRV_4988, // A4988 connected + DRV_2130 // TMC2130 connected +} drv_type; + +drv_type initDriver(); +drv_type getDrvType(); + +#endif // STEPPERS_H__ diff --git a/F0-nolib/CANbus_stepper/src/usb.c b/F0-nolib/CANbus_stepper/src/usb.c index a63b728..e8b4c52 100644 --- a/F0-nolib/CANbus_stepper/src/usb.c +++ b/F0-nolib/CANbus_stepper/src/usb.c @@ -23,53 +23,33 @@ #include "usb.h" #include "usb_lib.h" -#include // memcpy, memmove +#include "usart.h" -// incoming buffer size -#define IDATASZ (256) -static uint8_t incoming_data[IDATASZ]; -static uint8_t ovfl = 0; -static uint16_t idatalen = 0; -static int8_t usbON = 0; // ==1 when USB fully configured -static volatile uint8_t tx_succesfull = 0; +static volatile uint8_t tx_succesfull = 1; +static volatile uint8_t rxNE = 0; // interrupt IN handler (never used?) -static uint16_t EP1_Handler(ep_t ep){ - uint8_t ep0buf[11]; - if (ep.rx_flag){ - EP_Read(1, ep0buf); - ep.status = SET_VALID_TX(ep.status); - ep.status = KEEP_STAT_RX(ep.status); - }else if (ep.tx_flag){ - ep.status = SET_VALID_RX(ep.status); - ep.status = SET_STALL_TX(ep.status); - } - return ep.status; +static void EP1_Handler(){ + uint16_t epstatus = KEEP_DTOG(USB->EPnR[1]); + if(RX_FLAG(epstatus)) epstatus = (epstatus & ~USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_RX; // set valid RX + else epstatus = epstatus & ~(USB_EPnR_STAT_TX|USB_EPnR_STAT_RX); + // clear CTR + epstatus = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)); + USB->EPnR[1] = epstatus; } -// data IN/OUT handler -static uint16_t EP23_Handler(ep_t ep){ - if(ep.rx_flag){ - int rd = ep.rx_cnt, rest = IDATASZ - idatalen; - if(rd){ - if(rd <= rest){ - idatalen += EP_Read(2, &incoming_data[idatalen]); - ovfl = 0; - }else{ - ep.status = SET_NAK_RX(ep.status); - ovfl = 1; - return ep.status; - } - } - ep.status = CLEAR_DTOG_RX(ep.status); - ep.status = CLEAR_DTOG_TX(ep.status); - ep.status = SET_STALL_TX(ep.status); - }else if (ep.tx_flag){ - ep.status = KEEP_STAT_TX(ep.status); - tx_succesfull = 1; - } - ep.status = SET_VALID_RX(ep.status); - return ep.status; +// data IN/OUT handlers +static void transmit_Handler(){ // EP3IN + tx_succesfull = 1; + uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[3]); + // clear CTR keep DTOGs & STATs + USB->EPnR[3] = (epstatus & ~(USB_EPnR_CTR_TX)); // clear TX ctr +} + +static void receive_Handler(){ // EP2OUT + rxNE = 1; + uint16_t epstatus = KEEP_DTOG_STAT(USB->EPnR[2]); + USB->EPnR[2] = (epstatus & ~(USB_EPnR_CTR_RX)); // clear RX ctr } void USB_setup(){ @@ -77,7 +57,7 @@ void USB_setup(){ RCC->CFGR3 &= ~RCC_CFGR3_USBSW; // reset USB RCC->CR2 |= RCC_CR2_HSI48ON; // turn ON HSI48 uint32_t tmout = 16000000; - while(!(RCC->CR2 & RCC_CR2_HSI48RDY)){if(--tmout == 0) break; IWDG->KR = IWDG_REFRESH;} + while(!(RCC->CR2 & RCC_CR2_HSI48RDY)){if(--tmout == 0) break;} FLASH->ACR = FLASH_ACR_PRFTBE | FLASH_ACR_LATENCY; CRS->CFGR &= ~CRS_CFGR_SYNCSRC; CRS->CFGR |= CRS_CFGR_SYNCSRC_1; // USB SOF selected as sync source @@ -85,7 +65,7 @@ void USB_setup(){ CRS->CR |= CRS_CR_CEN; // enable freq counter & block CRS->CFGR as read-only RCC->CFGR |= RCC_CFGR_SW; // allow RESET and CTRM interrupts - USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM; + USB->CNTR = USB_CNTR_RESETM | USB_CNTR_WKUPM; // clear flags USB->ISTR = 0; // and activate pullup @@ -93,89 +73,109 @@ void USB_setup(){ NVIC_EnableIRQ(USB_IRQn); } -void usb_proc(){ - if(USB_GetState() == USB_CONFIGURE_STATE){ // USB configured - activate other endpoints - if(!usbON){ // endpoints not activated - // make new BULK endpoint - // Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features) - EP_Init(1, EP_TYPE_INTERRUPT, 10, 0, EP1_Handler); // IN1 - transmit - EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, EP23_Handler); // OUT2 - receive data - EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, EP23_Handler); // IN3 - transmit data - usbON = 1; - } - }else{ - usbON = 0; + +static int usbwr(const uint8_t *buf, uint16_t l){ + uint32_t ctra = 1000000; + while(--ctra && tx_succesfull == 0){ + IWDG->KR = IWDG_REFRESH; + } + tx_succesfull = 0; + EP_Write(3, buf, l); + ctra = 1000000; + while(--ctra && tx_succesfull == 0){ + IWDG->KR = IWDG_REFRESH; + } + if(tx_succesfull == 0){usbON = 0; return 1;} // usb is OFF? + return 0; +} + +static uint8_t usbbuff[USB_TXBUFSZ-1]; // temporary buffer (63 - to prevent need of ZLP) +static uint8_t buflen = 0; // amount of symbols in usbbuff + +// send next up to 63 bytes of data in usbbuff +static void send_next(){ + if(!buflen || !tx_succesfull) return; + tx_succesfull = 0; + EP_Write(3, usbbuff, buflen); + buflen = 0; +} + +// unblocking sending - just fill a buffer +void USB_send(const uint8_t *buf, uint16_t len){ + if(!usbON || !len) return; + if(len > USB_TXBUFSZ-1 - buflen){ + usbwr(usbbuff, buflen); + buflen = 0; + } + if(len > USB_TXBUFSZ-1){ + USB_send_blk(buf, len); + return; + } + while(len--) usbbuff[buflen++] = *buf++; +} + +// send zero-terminated string +void USB_sendstr(const char *str){ + uint16_t l = 0; + const char *ptr = str; + while(*ptr++ && l < 512) ++l; + USB_send((uint8_t*)str, l); +} + +// blocking sending +void USB_send_blk(const uint8_t *buf, uint16_t len){ + if(!usbON || !len) return; // USB disconnected + if(buflen){ + usbwr(usbbuff, buflen); + buflen = 0; + } + int needzlp = 0; + while(len){ + if(len == USB_TXBUFSZ) needzlp = 1; + uint16_t s = (len > USB_TXBUFSZ) ? USB_TXBUFSZ : len; + if(usbwr(buf, s)) return; + len -= s; + buf += s; + } + if(needzlp){ + usbwr(NULL, 0); } } -void USB_send(const char *buf){ - uint16_t l = 0, ctr = 0; - const char *p = buf; - while(*p++) ++l; - while(l){ - IWDG->KR = IWDG_REFRESH; - uint16_t s = (l > USB_TXBUFSZ) ? USB_TXBUFSZ : l; - tx_succesfull = 0; - EP_Write(3, (uint8_t*)&buf[ctr], s); - uint32_t ctra = 1000000; - while(--ctra && tx_succesfull == 0){IWDG->KR = IWDG_REFRESH;} - l -= s; - ctr += s; +void usb_proc(){ + switch(USB_Dev.USB_Status){ + case USB_STATE_CONFIGURED: + // make new BULK endpoint + // Buffer have 1024 bytes, but last 256 we use for CAN bus (30.2 of RM: USB main features) + EP_Init(1, EP_TYPE_INTERRUPT, USB_EP1BUFSZ, 0, EP1_Handler); // IN1 - transmit + EP_Init(2, EP_TYPE_BULK, 0, USB_RXBUFSZ, receive_Handler); // OUT2 - receive data + EP_Init(3, EP_TYPE_BULK, USB_TXBUFSZ, 0, transmit_Handler); // IN3 - transmit data + USB_Dev.USB_Status = USB_STATE_CONNECTED; + break; + case USB_STATE_DEFAULT: + case USB_STATE_ADDRESSED: + if(usbON){ + usbON = 0; + } + break; + default: // USB_STATE_CONNECTED - send next data portion + if(!usbON) return; + send_next(); } } /** - * @brief USB_receive - read first received text string - * @param buf (i) - buffer for received data - * @param bufsize - its size + * @brief USB_receive + * @param buf (i) - buffer[64] for received data * @return amount of received bytes */ -int USB_receive(char *buf, int bufsize){ - if(bufsize<1 || !idatalen) return 0; - IWDG->KR = IWDG_REFRESH; - int stlen = 0, i; - for(i = 0; i < idatalen; ++i){ - if(incoming_data[i] == '\n'){ - stlen = i+1; - break; - } - } - if(i == idatalen || stlen == 0) return 0; - /* - char x[] = "USB got x:\n"; - x[8] = '0' + stlen; - usart_send_blck(x); - usart_send_blck((char*)incoming_data); - usart_send_blck("\n"); - */ - USB->CNTR = 0; - int sz = (stlen > bufsize) ? bufsize : stlen, rest = idatalen - sz; - memcpy(buf, incoming_data, sz); - buf[sz] = 0; - /* - usart_send_blck("buf:\n"); - usart_send_blck((char*)buf); - usart_send_blck("\n"); - */ - if(rest > 0){ - memmove(incoming_data, &incoming_data[sz], rest); - idatalen = rest; - }else idatalen = 0; - if(ovfl){ - EP23_Handler(endpoints[2]); - uint16_t epstatus = USB->EPnR[2]; - epstatus = CLEAR_DTOG_RX(epstatus); - epstatus = SET_VALID_RX(epstatus); - USB->EPnR[2] = epstatus; - } - USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM; +uint8_t USB_receive(uint8_t *buf){ + if(!usbON || !rxNE) return 0; + uint8_t sz = EP_Read(2, buf); + uint16_t epstatus = KEEP_DTOG(USB->EPnR[2]); + // keep stat_tx & set ACK rx + USB->EPnR[2] = (epstatus & ~(USB_EPnR_STAT_TX)) ^ USB_EPnR_STAT_RX; + rxNE = 0; return sz; } -/** - * @brief USB_configured - * @return 1 if USB is in configured state - */ -int USB_configured(){ - return usbON; -} diff --git a/F0-nolib/CANbus_stepper/src/usb.h b/F0-nolib/CANbus_stepper/src/usb.h index 75d22b4..c888a57 100644 --- a/F0-nolib/CANbus_stepper/src/usb.h +++ b/F0-nolib/CANbus_stepper/src/usb.h @@ -28,10 +28,14 @@ #define BUFFSIZE (64) +// send string with constant length +#define USND(str) do{USB_send((uint8_t*)str, sizeof(str)-1);}while(0) + void USB_setup(); void usb_proc(); -void USB_send(const char *buf); -int USB_receive(char *buf, int bufsize); -int USB_configured(); +void USB_send(const uint8_t *buf, uint16_t len); +void USB_sendstr(const char *str); +void USB_send_blk(const uint8_t *buf, uint16_t len); +uint8_t USB_receive(uint8_t *buf); #endif // __USB_H__ diff --git a/F0-nolib/CANbus_stepper/src/usb_defs.h b/F0-nolib/CANbus_stepper/src/usb_defs.h index d9b6e22..f7e1339 100644 --- a/F0-nolib/CANbus_stepper/src/usb_defs.h +++ b/F0-nolib/CANbus_stepper/src/usb_defs.h @@ -27,22 +27,27 @@ #include +// max endpoints number +#define STM32ENDPOINTS 8 /** * Buffers size definition **/ // !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!! -#define USB_BTABLE_SIZE 1024 -// first 64 bytes of USB_BTABLE are registers! -#define USB_EP0_BASEADDR 64 +#define USB_BTABLE_SIZE 768 // for USB FS EP0 buffers are from 8 to 64 bytes long (64 for PL2303) #define USB_EP0_BUFSZ 64 // USB transmit buffer size (64 for PL2303) #define USB_TXBUFSZ 64 // USB receive buffer size (64 for PL2303) #define USB_RXBUFSZ 64 +// EP1 - interrupt - buffer size +#define USB_EP1BUFSZ 8 #define USB_BTABLE_BASE 0x40006000 + +#ifdef USB_BTABLE #undef USB_BTABLE +#endif #define USB_BTABLE ((USB_BtableDef *)(USB_BTABLE_BASE)) #define USB_ISTR_EPID 0x0000000F #define USB_FNR_LSOF_0 0x00000800 @@ -74,15 +79,8 @@ #define USB_TypeDef USB_TypeDef_custom typedef struct{ - __IO uint32_t EPnR[8]; - __IO uint32_t RESERVED1; - __IO uint32_t RESERVED2; - __IO uint32_t RESERVED3; - __IO uint32_t RESERVED4; - __IO uint32_t RESERVED5; - __IO uint32_t RESERVED6; - __IO uint32_t RESERVED7; - __IO uint32_t RESERVED8; + __IO uint32_t EPnR[STM32ENDPOINTS]; + __IO uint32_t RESERVED[STM32ENDPOINTS]; __IO uint32_t CNTR; __IO uint32_t ISTR; __IO uint32_t FNR; @@ -100,7 +98,7 @@ typedef struct{ } USB_EPDATA_TypeDef; typedef struct{ - __IO USB_EPDATA_TypeDef EP[8]; + __IO USB_EPDATA_TypeDef EP[STM32ENDPOINTS]; } USB_BtableDef; #endif // __USB_DEFS_H__ diff --git a/F0-nolib/CANbus_stepper/src/usb_lib.c b/F0-nolib/CANbus_stepper/src/usb_lib.c index 689af3e..9449ca9 100644 --- a/F0-nolib/CANbus_stepper/src/usb_lib.c +++ b/F0-nolib/CANbus_stepper/src/usb_lib.c @@ -20,17 +20,14 @@ * MA 02110-1301, USA. * */ -#include "usb_lib.h" + #include -#include // memcpy +#include "usb_lib.h" -#ifdef EBUG -#undef EBUG -#endif +ep_t endpoints[STM32ENDPOINTS]; -ep_t endpoints[ENDPOINTS_NUM]; - -static usb_dev_t USB_Dev; +usb_dev_t USB_Dev; +uint8_t usbON = 0; static usb_LineCoding lineCoding = {115200, 0, 0, 8}; static config_pack_t setup_packet; static uint8_t ep0databuf[EP0DATABUF_SIZE]; @@ -157,7 +154,6 @@ void WEAK break_handler(){ // handler of vendor requests void WEAK vendor_handler(config_pack_t *packet){ if(packet->bmRequestType & 0x80){ // read - //SEND("Read"); uint8_t c; switch(packet->wValue){ case 0x8484: @@ -179,8 +175,31 @@ void WEAK vendor_handler(config_pack_t *packet){ } static void wr0(const uint8_t *buf, uint16_t size){ - if(setup_packet.wLength < size) size = setup_packet.wLength; - EP_WriteIRQ(0, buf, size); + if(setup_packet.wLength < size) size = setup_packet.wLength; // shortened request + if(size < endpoints[0].txbufsz){ + EP_WriteIRQ(0, buf, size); + return; + } + while(size){ + uint16_t l = size; + if(l > endpoints[0].txbufsz) l = endpoints[0].txbufsz; + EP_WriteIRQ(0, buf, l); + buf += l; + size -= l; + uint8_t needzlp = (l == endpoints[0].txbufsz) ? 1 : 0; + if(size || needzlp){ // send last data buffer + uint16_t status = KEEP_DTOG(USB->EPnR[0]); + // keep DTOGs, clear CTR_RX,TX, set TX VALID, leave stat_Rx + USB->EPnR[0] = (status & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX|USB_EPnR_STAT_RX)) + ^ USB_EPnR_STAT_TX; + uint32_t ctr = 1000000; + while(--ctr && (USB->ISTR & USB_ISTR_CTR) == 0){IWDG->KR = IWDG_REFRESH;}; + if((USB->ISTR & USB_ISTR_CTR) == 0){ + return; + } + if(needzlp) EP_WriteIRQ(0, (uint8_t*)0, 0); + } + } } static inline void get_descriptor(){ @@ -207,7 +226,6 @@ static inline void get_descriptor(){ wr0(USB_DeviceQualifierDescriptor, USB_DeviceQualifierDescriptor[0]); break; default: - ; break; } } @@ -223,10 +241,9 @@ static inline void std_d2h_req(){ EP_WriteIRQ(0, (uint8_t *)&status, 2); // send status: Bus Powered break; case GET_CONFIGURATION: - EP_WriteIRQ(0, &configuration, 1); + EP_WriteIRQ(0, &configuration, 1); break; default: - ; break; } } @@ -239,11 +256,10 @@ static inline void std_h2d_req(){ break; case SET_CONFIGURATION: // Now device configured - USB_Dev.USB_Status = USB_CONFIGURE_STATE; + USB_Dev.USB_Status = USB_STATE_CONFIGURED; configuration = setup_packet.wValue; break; default: - ; break; } } @@ -256,14 +272,13 @@ bmRequestType: 76543210 */ /** * Endpoint0 (control) handler - * @param ep - endpoint state - * @return data written to EP0R */ -static uint16_t EP0_Handler(ep_t ep){ - uint16_t epstatus = ep.status; // EP0R on input -> return this value after modifications +static void EP0_Handler(){ + uint16_t epstatus = USB->EPnR[0]; // EP0R on input -> return this value after modifications uint8_t reqtype = setup_packet.bmRequestType & 0x7f; uint8_t dev2host = (setup_packet.bmRequestType & 0x80) ? 1 : 0; - if ((ep.rx_flag) && (ep.setup_flag)){ + int rxflag = RX_FLAG(epstatus); + if(rxflag && SETUP_FLAG(epstatus)){ switch(reqtype){ case STANDARD_DEVICE_REQUEST_TYPE: // standard device request if(dev2host){ @@ -272,20 +287,14 @@ static uint16_t EP0_Handler(ep_t ep){ std_h2d_req(); EP_WriteIRQ(0, (uint8_t *)0, 0); } - epstatus = SET_NAK_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); break; case STANDARD_ENDPOINT_REQUEST_TYPE: // standard endpoint request if(setup_packet.bRequest == CLEAR_FEATURE){ EP_WriteIRQ(0, (uint8_t *)0, 0); - epstatus = SET_NAK_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); } break; case VENDOR_REQUEST_TYPE: vendor_handler(&setup_packet); - epstatus = SET_NAK_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); break; case CONTROL_REQUEST_TYPE: switch(setup_packet.bRequest){ @@ -295,51 +304,43 @@ static uint16_t EP0_Handler(ep_t ep){ case SET_LINE_CODING: // omit this for next stage, when data will come break; case SET_CONTROL_LINE_STATE: + usbON = 1; clstate_handler(setup_packet.wValue); break; case SEND_BREAK: + usbON = 0; break_handler(); break; default: break; } - //if(!dev2host) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement if(setup_packet.bRequest != GET_LINE_CODING) EP_WriteIRQ(0, (uint8_t *)0, 0); // write acknowledgement - epstatus = SET_VALID_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); break; default: EP_WriteIRQ(0, (uint8_t *)0, 0); - epstatus = SET_NAK_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); } - }else if (ep.rx_flag){ // got data over EP0 or host acknowlegement - if(ep.rx_cnt){ - //EP_WriteIRQ(0, (uint8_t *)0, 0); + }else if(rxflag){ // got data over EP0 or host acknowlegement + if(endpoints[0].rx_cnt){ if(setup_packet.bRequest == SET_LINE_CODING){ linecoding_handler((usb_LineCoding*)ep0databuf); } } - // wait for new data from host - epstatus = SET_VALID_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); - } else if (ep.tx_flag){ // package transmitted + } else if(TX_FLAG(epstatus)){ // package transmitted // now we can change address after enumeration if ((USB->DADDR & USB_DADDR_ADD) != USB_Dev.USB_Addr){ USB->DADDR = USB_DADDR_EF | USB_Dev.USB_Addr; // change state to ADRESSED - USB_Dev.USB_Status = USB_ADRESSED_STATE; + USB_Dev.USB_Status = USB_STATE_ADDRESSED; } - // end of transaction - epstatus = CLEAR_DTOG_RX(epstatus); - epstatus = CLEAR_DTOG_TX(epstatus); - epstatus = SET_VALID_RX(epstatus); - epstatus = SET_VALID_TX(epstatus); } - return epstatus; + epstatus = KEEP_DTOG(USB->EPnR[0]); + if(rxflag) epstatus ^= USB_EPnR_STAT_TX; // start ZLP/data transmission + else epstatus &= ~USB_EPnR_STAT_TX; // or leave unchanged + // keep DTOGs, clear CTR_RX,TX, set RX VALID + USB->EPnR[0] = (epstatus & ~(USB_EPnR_CTR_RX|USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_RX; } -static uint16_t lastaddr = USB_EP0_BASEADDR; +static uint16_t lastaddr = LASTADDR_DEFAULT; /** * Endpoint initialisation * !!! when working with CAN bus change USB_BTABLE_SIZE to 768 !!! @@ -350,13 +351,13 @@ static uint16_t lastaddr = USB_EP0_BASEADDR; * @param uint16_t (*func)(ep_t *ep) - EP handler function * @return 0 if all OK */ -int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)){ - if(number >= ENDPOINTS_NUM) return 4; // out of configured amount +int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)()){ + if(number >= STM32ENDPOINTS) return 4; // out of configured amount if(txsz > USB_BTABLE_SIZE || rxsz > USB_BTABLE_SIZE) return 1; // buffer too large if(lastaddr + txsz + rxsz >= USB_BTABLE_SIZE) return 2; // out of btable USB->EPnR[number] = (type << 9) | (number & USB_EPnR_EA); USB->EPnR[number] ^= USB_EPnR_STAT_RX | USB_EPnR_STAT_TX_1; - if(rxsz & 1 || rxsz > 992) return 3; // wrong rx buffer size + if(rxsz & 1 || rxsz > 512) return 3; // wrong rx buffer size uint16_t countrx = 0; if(rxsz < 64) countrx = rxsz / 2; else{ @@ -365,6 +366,7 @@ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t } USB_BTABLE->EP[number].USB_ADDR_TX = lastaddr; endpoints[number].tx_buf = (uint16_t *)(USB_BTABLE_BASE + lastaddr); + endpoints[number].txbufsz = txsz; lastaddr += txsz; USB_BTABLE->EP[number].USB_COUNT_TX = 0; USB_BTABLE->EP[number].USB_ADDR_RX = lastaddr; @@ -380,56 +382,48 @@ int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t void usb_isr(){ if (USB->ISTR & USB_ISTR_RESET){ // Reinit registers - USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM; + USB->CNTR = USB_CNTR_RESETM | USB_CNTR_CTRM | USB_CNTR_SUSPM | USB_CNTR_WKUPM; USB->ISTR = 0; // Endpoint 0 - CONTROL // ON USB LS size of EP0 may be 8 bytes, but on FS it should be 64 bytes! - lastaddr = USB_EP0_BASEADDR; // roll back to beginning of buffer + lastaddr = LASTADDR_DEFAULT; // roll back to beginning of buffer + EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler); // clear address, leave only enable bit USB->DADDR = USB_DADDR_EF; - USB_Dev.USB_Status = USB_DEFAULT_STATE; - if(EP_Init(0, EP_TYPE_CONTROL, USB_EP0_BUFSZ, USB_EP0_BUFSZ, EP0_Handler)){ - return; - } + // state is default - wait for enumeration + USB_Dev.USB_Status = USB_STATE_DEFAULT; } if(USB->ISTR & USB_ISTR_CTR){ // EP number uint8_t n = USB->ISTR & USB_ISTR_EPID; // copy status register uint16_t epstatus = USB->EPnR[n]; - // Calculate flags - endpoints[n].rx_flag = (epstatus & USB_EPnR_CTR_RX) ? 1 : 0; - endpoints[n].setup_flag = (epstatus & USB_EPnR_SETUP) ? 1 : 0; - endpoints[n].tx_flag = (epstatus & USB_EPnR_CTR_TX) ? 1 : 0; // copy received bytes amount endpoints[n].rx_cnt = USB_BTABLE->EP[n].USB_COUNT_RX & 0x3FF; // low 10 bits is counter // check direction if(USB->ISTR & USB_ISTR_DIR){ // OUT interrupt - receive data, CTR_RX==1 (if CTR_TX == 1 - two pending transactions: receive following by transmit) if(n == 0){ // control endpoint if(epstatus & USB_EPnR_SETUP){ // setup packet -> copy data to conf_pack - memcpy(&setup_packet, endpoints[0].rx_buf, sizeof(setup_packet)); + EP_Read(0, (uint8_t*)&setup_packet); ep0dbuflen = 0; // interrupt handler will be called later }else if(epstatus & USB_EPnR_CTR_RX){ // data packet -> push received data to ep0databuf ep0dbuflen = endpoints[0].rx_cnt; - memcpy(ep0databuf, endpoints[0].rx_buf, ep0dbuflen); + EP_Read(0, (uint8_t*)&ep0databuf); } } - }else{ // IN interrupt - transmit data, only CTR_TX == 1 - // enumeration end could be here (if EP0) } - // prepare status field for EP handler - endpoints[n].status = epstatus; - // call EP handler (even if it will change EPnR, it should return new status) - epstatus = endpoints[n].func(endpoints[n]); - // keep DTOG state - epstatus = KEEP_DTOG_TX(epstatus); - epstatus = KEEP_DTOG_RX(epstatus); - // clear all RX/TX flags - epstatus = CLEAR_CTR_RX(epstatus); - epstatus = CLEAR_CTR_TX(epstatus); - // refresh EPnR - USB->EPnR[n] = epstatus; + // call EP handler + if(endpoints[n].func) endpoints[n].func(endpoints[n]); + } + if(USB->ISTR & USB_ISTR_SUSP){ // suspend -> still no connection, may sleep + usbON = 0; + USB->CNTR |= USB_CNTR_FSUSP | USB_CNTR_LPMODE; + USB->ISTR = ~USB_ISTR_SUSP; + } + if(USB->ISTR & USB_ISTR_WKUP){ // wakeup + USB->CNTR &= ~(USB_CNTR_FSUSP | USB_CNTR_LPMODE); // clear suspend flags + USB->ISTR = ~USB_ISTR_WKUP; } } @@ -458,13 +452,10 @@ void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size){ * @param size - its size */ void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size){ - uint16_t status = USB->EPnR[number]; EP_WriteIRQ(number, buf, size); - status = SET_NAK_RX(status); - status = SET_VALID_TX(status); - status = KEEP_DTOG_TX(status); - status = KEEP_DTOG_RX(status); - USB->EPnR[number] = status; + uint16_t status = KEEP_DTOG(USB->EPnR[number]); + // keep DTOGs, clear CTR_TX & set TX VALID to start transmission + USB->EPnR[number] = (status & ~(USB_EPnR_CTR_TX)) ^ USB_EPnR_STAT_TX; } /* @@ -480,8 +471,3 @@ int EP_Read(uint8_t number, uint8_t *buf){ } return n; } - -// USB status -uint8_t USB_GetState(){ - return USB_Dev.USB_Status; -} diff --git a/F0-nolib/CANbus_stepper/src/usb_lib.h b/F0-nolib/CANbus_stepper/src/usb_lib.h index 0651e5f..92eea1f 100644 --- a/F0-nolib/CANbus_stepper/src/usb_lib.h +++ b/F0-nolib/CANbus_stepper/src/usb_lib.h @@ -29,9 +29,8 @@ #include "usb_defs.h" #define EP0DATABUF_SIZE (64) +#define LASTADDR_DEFAULT (STM32ENDPOINTS * 8) -// Max EP amount (EP0 + other used) -#define ENDPOINTS_NUM 4 // bmRequestType & 0x7f #define STANDARD_DEVICE_REQUEST_TYPE 0 #define STANDARD_ENDPOINT_REQUEST_TYPE 2 @@ -77,31 +76,21 @@ #define STRING_SN_DESCRIPTOR 0x303 #define DEVICE_QUALIFIER_DESCRIPTOR 0x600 -// EPnR bits manipulation -#define CLEAR_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? R : (R & (~USB_EPnR_DTOG_RX)) -#define SET_DTOG_RX(R) (R & USB_EPnR_DTOG_RX) ? (R & (~USB_EPnR_DTOG_RX)) : R -#define TOGGLE_DTOG_RX(R) (R | USB_EPnR_DTOG_RX) -#define KEEP_DTOG_RX(R) (R & (~USB_EPnR_DTOG_RX)) -#define CLEAR_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? R : (R & (~USB_EPnR_DTOG_TX)) -#define SET_DTOG_TX(R) (R & USB_EPnR_DTOG_TX) ? (R & (~USB_EPnR_DTOG_TX)) : R -#define TOGGLE_DTOG_TX(R) (R | USB_EPnR_DTOG_TX) -#define KEEP_DTOG_TX(R) (R & (~USB_EPnR_DTOG_TX)) -#define SET_VALID_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX) | (R & (~USB_EPnR_STAT_RX)) -#define SET_NAK_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_1) | (R & (~USB_EPnR_STAT_RX)) -#define SET_STALL_RX(R) ((R & USB_EPnR_STAT_RX) ^ USB_EPnR_STAT_RX_0) | (R & (~USB_EPnR_STAT_RX)) -#define KEEP_STAT_RX(R) (R & (~USB_EPnR_STAT_RX)) -#define SET_VALID_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX) | (R & (~USB_EPnR_STAT_TX)) -#define SET_NAK_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_1) | (R & (~USB_EPnR_STAT_TX)) -#define SET_STALL_TX(R) ((R & USB_EPnR_STAT_TX) ^ USB_EPnR_STAT_TX_0) | (R & (~USB_EPnR_STAT_TX)) -#define KEEP_STAT_TX(R) (R & (~USB_EPnR_STAT_TX)) -#define CLEAR_CTR_RX(R) (R & (~USB_EPnR_CTR_RX)) -#define CLEAR_CTR_TX(R) (R & (~USB_EPnR_CTR_TX)) -#define CLEAR_CTR_RX_TX(R) (R & (~(USB_EPnR_CTR_TX | USB_EPnR_CTR_RX))) +#define RX_FLAG(epstat) (epstat & USB_EPnR_CTR_RX) +#define TX_FLAG(epstat) (epstat & USB_EPnR_CTR_TX) +#define SETUP_FLAG(epstat) (epstat & USB_EPnR_SETUP) -// USB state: uninitialized, addressed, ready for use -#define USB_DEFAULT_STATE 0 -#define USB_ADRESSED_STATE 1 -#define USB_CONFIGURE_STATE 2 +// EPnR bits manipulation +#define KEEP_DTOG_STAT(EPnR) (EPnR & ~(USB_EPnR_STAT_RX|USB_EPnR_STAT_TX|USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) +#define KEEP_DTOG(EPnR) (EPnR & ~(USB_EPnR_DTOG_RX|USB_EPnR_DTOG_TX)) + +// USB state: uninitialized, addressed, ready for use, client connected +typedef enum{ + USB_STATE_DEFAULT, + USB_STATE_ADDRESSED, + USB_STATE_CONFIGURED, + USB_STATE_CONNECTED +} USB_state; // EP types #define EP_TYPE_BULK 0x00 @@ -145,13 +134,10 @@ typedef struct { // endpoints state typedef struct __ep_t{ uint16_t *tx_buf; // transmission buffer address + uint16_t txbufsz; // transmission buffer size uint8_t *rx_buf; // reception buffer address - uint16_t (*func)(); // endpoint action function - uint16_t status; // status flags - unsigned rx_cnt : 10; // received data counter - unsigned tx_flag : 1; // transmission flag - unsigned rx_flag : 1; // reception flag - unsigned setup_flag : 1; // this is setup packet (only for EP0) + void (*func)(); // endpoint action function + uint16_t rx_cnt; // received data counter } ep_t; // USB status & its address @@ -184,19 +170,20 @@ typedef struct { } __attribute__ ((packed)) usb_cdc_notification; extern ep_t endpoints[]; +extern usb_dev_t USB_Dev; +extern uint8_t usbON; void USB_Init(); uint8_t USB_GetState(); -int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, uint16_t (*func)(ep_t ep)); +int EP_Init(uint8_t number, uint8_t type, uint16_t txsz, uint16_t rxsz, void (*func)()); void EP_WriteIRQ(uint8_t number, const uint8_t *buf, uint16_t size); void EP_Write(uint8_t number, const uint8_t *buf, uint16_t size); int EP_Read(uint8_t number, uint8_t *buf); usb_LineCoding getLineCoding(); - -void WEAK linecoding_handler(usb_LineCoding *lc); -void WEAK clstate_handler(uint16_t val); -void WEAK break_handler(); -void WEAK vendor_handler(config_pack_t *packet); +void linecoding_handler(usb_LineCoding *lc); +void clstate_handler(uint16_t val); +void break_handler(); +void vendor_handler(config_pack_t *packet); #endif // __USB_LIB_H__ diff --git a/F0-nolib/Snippets/Flash_EEPROM/flash.c b/F0-nolib/Snippets/Flash_EEPROM/flash.c index ab04d09..5e6525c 100644 --- a/F0-nolib/Snippets/Flash_EEPROM/flash.c +++ b/F0-nolib/Snippets/Flash_EEPROM/flash.c @@ -20,143 +20,200 @@ * MA 02110-1301, USA. * */ -#include "stm32f0.h" + +/** + ATTENTION!! + This things works only if you will add next section: + + .myvars : + { + . = ALIGN(1024); + __varsstart = ABSOLUTE(.); + KEEP(*(.myvars)); + } > rom + + after section .data +*/ +#include +#include "adc.h" +#include "flash.h" +#include "proto.h" // printout #include // memcpy -#include "flash.h" -#include "usart.h" +// max amount of Config records stored (will be recalculate in flashstorage_init() +static uint32_t maxCnum = FLASH_BLOCK_SIZE / sizeof(user_conf); -// start of configuration data in flash (from 15kB, one kB size) -#define FLASH_CONF_START_ADDR ((uint32_t)0x08003C00) -static const int maxnum = 1024 / sizeof(user_conf); +#define USERCONF_INITIALIZER { \ + .userconf_sz = sizeof(user_conf) \ + ,.defflags = 0 \ + ,.CANspeed = 100 \ + } -user_conf the_conf = { - .userconf_sz = sizeof(user_conf) - ,.devID = 0 - ,.v12numerator = 1 - ,.v12denominator = 1 - ,.i12numerator = 1 - ,.i12denominator = 1 - ,.v33denominator = 1 - ,.v33numerator = 1 - ,.ESW_thres = 150 -}; +static int erase_flash(const void*, const void*); +static int write2flash(const void*, const void*, uint32_t); +// don't write `static` here, or get error: +// 'memcpy' forming offset 8 is out of the bounds [0, 4] of object '__varsstart' with type 'uint32_t' +const user_conf *Flash_Data = (const user_conf *)(&__varsstart); -static int erase_flash(); +user_conf the_conf = USERCONF_INITIALIZER; -static int get_gooddata(){ - user_conf *c = (user_conf*) FLASH_CONF_START_ADDR; - // have data - move it to `the_conf` - int idx; -//write2trbuf("get_gooddata()\n"); - for(idx = 0; idx < maxnum; ++idx){ // find current settings index - first good - uint16_t sz = c[idx].userconf_sz; -/*write2trbuf("idx="); -put_int((int32_t) idx); -write2trbuf(", sz="); -put_uint((uint32_t) sz); -write2trbuf(", devID="); -put_uint((uint32_t) c[idx].devID); -write2trbuf(", ESW_thres="); -put_uint((uint32_t) c[idx].ESW_thres); -SENDBUF();*/ - if(sz != sizeof(user_conf)){ - if(sz == 0xffff) break; // first clear - else{ - return -2; // flash corrupt, need to erase +static int currentconfidx = -1; // index of current configuration + +/** + * @brief binarySearch - binary search in flash for last non-empty cell + * any struct searched should have its sizeof() @ the first field!!! + * @param l - left index + * @param r - right index (should be @1 less than last index!) + * @param start - starting address + * @param stor_size - size of structure to search + * @return index of non-empty cell or -1 + */ +static int binarySearch(int r, const uint8_t *start, int stor_size){ + int l = 0; + while(r >= l){ + int mid = l + (r - l) / 2; + const uint8_t *s = start + mid * stor_size; + if(*((const uint16_t*)s) == stor_size){ + if(*((const uint16_t*)(s + stor_size)) == 0xffff){ + return mid; + }else{ // element is to the right + l = mid + 1; } + }else{ // element is to the left + r = mid - 1; } } - return idx-1; // -1 if there's no data at all & flash is clear; maxnum-1 if flash is full + return -1; // not found } -void get_userconf(){ - user_conf *c = (user_conf*) FLASH_CONF_START_ADDR; - int idx = get_gooddata(); - if(idx < 0) return; // no data stored - memcpy(&the_conf, &c[idx], sizeof(user_conf)); +/** + * @brief flashstorage_init - initialization of user conf storage + * run in once @ start + */ +void flashstorage_init(){ + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + uint32_t flsz = FLASH_SIZE * 1024; // size in bytes + flsz -= (uint32_t)(&__varsstart) - FLASH_BASE; + maxCnum = flsz / sizeof(user_conf); +//SEND("flsz="); printu(flsz); +//SEND("\nmaxCnum="); printu(maxCnum); newline(); sendbuf(); + } + // -1 if there's no data at all & flash is clear; maxnum-1 if flash is full + currentconfidx = binarySearch((int)maxCnum-2, (const uint8_t*)Flash_Data, sizeof(user_conf)); + if(currentconfidx > -1){ + memcpy(&the_conf, &Flash_Data[currentconfidx], sizeof(user_conf)); + } } // store new configuration // @return 0 if all OK int store_userconf(){ + // maxnum - 3 means that there always should be at least one empty record after last data + // for binarySearch() checking that there's nothing more after it! + if(currentconfidx > (int)maxCnum - 3){ // there's no more place + currentconfidx = 0; + if(erase_flash(Flash_Data, (&__varsstart))) return 1; + }else ++currentconfidx; // take next data position (0 - within first run after firmware flashing) + return write2flash((const void*)&Flash_Data[currentconfidx], &the_conf, sizeof(the_conf)); +} + +static int write2flash(const void *start, const void *wrdata, uint32_t stor_size){ int ret = 0; - user_conf *c = (user_conf*) FLASH_CONF_START_ADDR; - int idx = get_gooddata(); - if(idx == -2 || idx == maxnum - 1){ // data corruption or there's no more place - idx = 0; - if(erase_flash()) return 1; - }else ++idx; // take next data position -/*write2trbuf("store_userconf()\nidx="); -put_int((int32_t) idx); -SENDBUF();*/ if (FLASH->CR & FLASH_CR_LOCK){ // unloch flash - FLASH->KEYR = FLASH_FKEY1; - FLASH->KEYR = FLASH_FKEY2; + FLASH->KEYR = FLASH_KEY1; + FLASH->KEYR = FLASH_KEY2; } while (FLASH->SR & FLASH_SR_BSY); - if(FLASH->SR & FLASH_SR_WRPERR) return 1; // write protection - FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; // clear all flags + if(FLASH->SR & FLASH_SR_WRPRTERR){ + MSG("Can't remove write protection\n"); + return 1; // write protection + } + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; // clear all flags FLASH->CR |= FLASH_CR_PG; - uint16_t *data = (uint16_t*) &the_conf; - uint16_t *address = (uint16_t*) &c[idx]; - uint32_t i, count = sizeof(user_conf) / 2; + const uint16_t *data = (const uint16_t*) wrdata; + volatile uint16_t *address = (volatile uint16_t*) start; + uint32_t i, count = (stor_size + 1) / 2; for (i = 0; i < count; ++i){ + IWDG->KR = IWDG_REFRESH; *(volatile uint16_t*)(address + i) = data[i]; while (FLASH->SR & FLASH_SR_BSY); - if(FLASH->SR & FLASH_SR_PGERR) ret = 1; // program error - meet not 0xffff - else while (!(FLASH->SR & FLASH_SR_EOP)); -/*write2trbuf("write byte "); -put_int((int32_t) i); -write2trbuf(", write value="); -put_uint(data[i]); -write2trbuf(", read value="); -put_uint(address[i]); -SENDBUF(); -if(ret){ -write2trbuf("PGERR"); -SENDBUF();*/ -} - FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; + if(FLASH->SR & FLASH_SR_PGERR){ + ret = 1; // program error - meet not 0xffff + MSG("FLASH_SR_PGERR\n"); + break; + }else while (!(FLASH->SR & FLASH_SR_EOP)); + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; } + FLASH->CR |= FLASH_CR_LOCK; // lock it back FLASH->CR &= ~(FLASH_CR_PG); + MSG("Flash stored\n"); return ret; } - -static int erase_flash(){ +/** + * @brief erase_flash - erase N pages of flash memory + * @param start - first address + * @param end - last address (or NULL if need to erase all flash remaining) + * @return 0 if succeed + */ +static int erase_flash(const void *start, const void *end){ int ret = 0; -/*write2trbuf("erase_flash()"); -SENDBUF();*/ - /* (1) Wait till no operation is on going */ - /* (2) Clear error & EOP bits */ - /* (3) Check that the Flash is unlocked */ - /* (4) Perform unlock sequence */ - while ((FLASH->SR & FLASH_SR_BSY) != 0){} /* (1) */ - FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPERR; /* (2) */ - /* if (FLASH->SR & FLASH_SR_EOP){ - FLASH->SR |= FLASH_SR_EOP; - }*/ - if ((FLASH->CR & FLASH_CR_LOCK) != 0){ /* (3) */ - FLASH->KEYR = FLASH_FKEY1; /* (4) */ - FLASH->KEYR = FLASH_FKEY2; + uint32_t nblocks = 1, flsz = 0; + if(!end){ // erase all remaining + if(FLASH_SIZE > 0 && FLASH_SIZE < 20000){ + flsz = FLASH_SIZE * 1024; // size in bytes + flsz -= (uint32_t)start - FLASH_BASE; + } + }else{ // erase a part + flsz = (uint32_t)end - (uint32_t)start; } - /* (1) Set the PER bit in the FLASH_CR register to enable page erasing */ - /* (2) Program the FLASH_AR register to select a page to erase */ - /* (3) Set the STRT bit in the FLASH_CR register to start the erasing */ - /* (4) Wait until the EOP flag in the FLASH_SR register set */ - /* (5) Clear EOP flag by software by writing EOP at 1 */ - /* (6) Reset the PER Bit to disable the page erase */ - FLASH->CR |= FLASH_CR_PER; /* (1) */ - FLASH->AR = FLASH_CONF_START_ADDR; /* (2) */ - FLASH->CR |= FLASH_CR_STRT; /* (3) */ - while(!(FLASH->SR & FLASH_SR_EOP)); - FLASH->SR |= FLASH_SR_EOP; /* (5)*/ - if(FLASH->SR & FLASH_SR_WRPERR){ /* Check Write protection error */ - ret = 1; - FLASH->SR |= FLASH_SR_WRPERR; /* Clear the flag by software by writing it at 1*/ + nblocks = flsz / FLASH_BLOCK_SIZE; + if(nblocks == 0 || nblocks >= FLASH_SIZE) return 1; + for(uint32_t i = 0; i < nblocks; ++i){ +#ifdef EBUG + SEND("Try to erase page #"); printu(i); newline(); sendbuf(); +#endif + IWDG->KR = IWDG_REFRESH; + /* (1) Wait till no operation is on going */ + /* (2) Clear error & EOP bits */ + /* (3) Check that the Flash is unlocked */ + /* (4) Perform unlock sequence */ + while ((FLASH->SR & FLASH_SR_BSY) != 0){} /* (1) */ + FLASH->SR = FLASH_SR_EOP | FLASH_SR_PGERR | FLASH_SR_WRPRTERR; /* (2) */ + /* if (FLASH->SR & FLASH_SR_EOP){ + FLASH->SR |= FLASH_SR_EOP; + }*/ + if ((FLASH->CR & FLASH_CR_LOCK) != 0){ /* (3) */ + FLASH->KEYR = FLASH_KEY1; /* (4) */ + FLASH->KEYR = FLASH_KEY2; + } + /* (1) Set the PER bit in the FLASH_CR register to enable page erasing */ + /* (2) Program the FLASH_AR register to select a page to erase */ + /* (3) Set the STRT bit in the FLASH_CR register to start the erasing */ + /* (4) Wait until the EOP flag in the FLASH_SR register set */ + /* (5) Clear EOP flag by software by writing EOP at 1 */ + /* (6) Reset the PER Bit to disable the page erase */ + FLASH->CR |= FLASH_CR_PER; /* (1) */ + FLASH->AR = (uint32_t)Flash_Data + i*FLASH_BLOCK_SIZE; /* (2) */ + FLASH->CR |= FLASH_CR_STRT; /* (3) */ + while(!(FLASH->SR & FLASH_SR_EOP)); + FLASH->SR |= FLASH_SR_EOP; /* (5)*/ + if(FLASH->SR & FLASH_SR_WRPRTERR){ /* Check Write protection error */ + ret = 1; + MSG("Write protection error!\n"); + FLASH->SR |= FLASH_SR_WRPRTERR; /* Clear the flag by software by writing it at 1*/ + break; + } + FLASH->CR &= ~FLASH_CR_PER; /* (6) */ } - FLASH->CR &= ~FLASH_CR_PER; /* (6) */ return ret; } +void dump_userconf(){ + SEND("userconf_addr="); printuhex((uint32_t)Flash_Data); + SEND("\nuserconf_sz="); printu(the_conf.userconf_sz); + SEND("\nflags="); printuhex(the_conf.defflags); + SEND("\nCANspeed="); printu(the_conf.CANspeed); + newline(); + sendbuf(); +} diff --git a/F0-nolib/Snippets/Flash_EEPROM/flash.h b/F0-nolib/Snippets/Flash_EEPROM/flash.h index 48bdb1d..dcccaac 100644 --- a/F0-nolib/Snippets/Flash_EEPROM/flash.h +++ b/F0-nolib/Snippets/Flash_EEPROM/flash.h @@ -1,5 +1,4 @@ /* - * geany_encoding=koi8-r * flash.h * * Copyright 2017 Edward V. Emelianov @@ -25,22 +24,27 @@ #ifndef __FLASH_H__ #define __FLASH_H__ -typedef struct{ - uint16_t userconf_sz; // size of data - uint16_t devID; // device address (id) - uint16_t ESW_thres; // ADC threshold for end-switches/Hall sensors - // calibration values for current/voltage sensors - uint16_t v12numerator; // 12V to motors - uint16_t v12denominator; - uint16_t i12numerator; // motors' current - uint16_t i12denominator; - uint16_t v33numerator; // 3.3V (vref) - uint16_t v33denominator; +#include "hardware.h" + +#define FLASH_BLOCK_SIZE (1024) +#define FLASH_SIZE_REG ((uint32_t)0x1FFFF7CC) +#define FLASH_SIZE *((uint16_t*)FLASH_SIZE_REG) + +/* + * struct to save user configurations + */ +typedef struct __attribute__((packed, aligned(4))){ + uint16_t userconf_sz; // "magick number" + uint8_t defflags; // default flags + uint16_t CANspeed; // default CAN speed } user_conf; -extern user_conf the_conf; +extern user_conf the_conf; // global user config (read from FLASH to RAM) +// data from ld-file: start address of storage +extern const uint32_t __varsstart; -void get_userconf(); +void flashstorage_init(); int store_userconf(); +void dump_userconf(); #endif // __FLASH_H__ diff --git a/F0-nolib/Snippets/printuhex.c b/F0-nolib/Snippets/printuhex.c index 34f1c33..c41f000 100644 --- a/F0-nolib/Snippets/printuhex.c +++ b/F0-nolib/Snippets/printuhex.c @@ -4,7 +4,6 @@ void printuhex(uint32_t val){ uint8_t *ptr = (uint8_t*)&val + 3; int8_t i, j; for(i = 0; i < 4; ++i, --ptr){ - if(*ptr == 0 && i != 3) continue; // omit leading zeros for(j = 1; j > -1; --j){ uint8_t half = (*ptr >> (4*j)) & 0x0f; if(half < 10) bufputchar(half + '0'); diff --git a/F0-nolib/inc/Fx/stm32f0.h b/F0-nolib/inc/Fx/stm32f0.h index bbf959f..a6065f0 100644 --- a/F0-nolib/inc/Fx/stm32f0.h +++ b/F0-nolib/inc/Fx/stm32f0.h @@ -182,6 +182,11 @@ TRUE_INLINE void StartHSI48(){ #define GPIO_MODER_MODER15_AF ((uint32_t)0x80000000) +/****************** FLASH Keys **********************************************/ +#define RDP_Key ((uint16_t)0x00A5) +#define FLASH_KEY1 ((uint32_t)0x45670123) +#define FLASH_KEY2 ((uint32_t)0xCDEF89AB) + /************************* ADC *************************/ /* inner termometer calibration values * Temp = (V30 - Vsense)/Avg_Slope + 30 diff --git a/F0-nolib/inc/ld/stm32f01234.ld b/F0-nolib/inc/ld/stm32f01234.ld index 930bf36..aaf4995 100644 --- a/F0-nolib/inc/ld/stm32f01234.ld +++ b/F0-nolib/inc/ld/stm32f01234.ld @@ -74,7 +74,8 @@ SECTIONS { .myvars : { . = ALIGN(1024); - KEEP(*(.myvars)) + __varsstart = ABSOLUTE(.); + KEEP(*(.myvars)); } > rom _ldata = LOADADDR(.data); diff --git a/F0-nolib/usbcdc/can.c b/F0-nolib/usbcdc/can.c index 91b23e0..d4bffb6 100644 --- a/F0-nolib/usbcdc/can.c +++ b/F0-nolib/usbcdc/can.c @@ -367,7 +367,7 @@ static void can_process_fifo(uint8_t fifo_num){ /* 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; + uint8_t len = box->RDTR & 0x0f; msg.length = len; msg.ID = box->RIR >> 21; //msg.filterNo = (box->RDTR >> 8) & 0xff; diff --git a/F0-nolib/usbcdc/proto.c b/F0-nolib/usbcdc/proto.c index 7aeba57..56c2972 100644 --- a/F0-nolib/usbcdc/proto.c +++ b/F0-nolib/usbcdc/proto.c @@ -167,7 +167,7 @@ static CAN_message *parseCANmsg(char *txt){ return NULL; } canmsg.ID = (uint16_t)(N&0x7ff); - SEND("ID="); printuhex(canmsg.ID); newline(); + //SEND("ID="); printuhex(canmsg.ID); newline(); ctr = 0; continue; } @@ -546,7 +546,6 @@ void printuhex(uint32_t val){ uint8_t *ptr = (uint8_t*)&val + 3; int8_t i, j; for(i = 0; i < 4; ++i, --ptr){ - if(*ptr == 0 && i != 3) continue; // omit leading zeros for(j = 1; j > -1; --j){ uint8_t half = (*ptr >> (4*j)) & 0x0f; if(half < 10) bufputchar(half + '0'); diff --git a/F0-nolib/usbcdc/usbcan.bin b/F0-nolib/usbcdc/usbcan.bin index 6630c83b8eb22e8f2f082645cde8646b464cbabf..6e94de4cecc8ffcbd20ba900434638ecec35145e 100755 GIT binary patch delta 2944 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