From 9fc1fd7ad6ceda4fb659b59b0db62eb8f1eba5e5 Mon Sep 17 00:00:00 2001 From: eddyem Date: Wed, 25 Jul 2018 20:27:25 +0300 Subject: [PATCH] testing CAN bus network version (without USB) --- STM32/Readme.md | 12 +- STM32/TSYS_controller/2DO | 1 - STM32/TSYS_controller/Makefile | 10 +- STM32/TSYS_controller/Readme.md | 42 +++- STM32/TSYS_controller/can.c | 280 ++++++++++++++++++++++++- STM32/TSYS_controller/can.h | 38 +++- STM32/TSYS_controller/can_process.c | 172 +++++++++++++++ STM32/TSYS_controller/can_process.h | 45 ++++ STM32/TSYS_controller/hardware.h | 5 +- STM32/TSYS_controller/i2c.c | 18 +- STM32/TSYS_controller/main.c | 155 +++++++++----- STM32/TSYS_controller/sensors_manage.c | 112 ++++++---- STM32/TSYS_controller/sensors_manage.h | 5 + STM32/TSYS_controller/tsys01.bin | Bin 11208 -> 14412 bytes STM32/TSYS_controller/tsys01.c.tags | 136 ++++++++++-- STM32/TSYS_controller/tsys01.geany | 11 +- STM32/TSYS_controller/usart.c | 14 ++ STM32/TSYS_controller/usart.h | 1 + 18 files changed, 914 insertions(+), 143 deletions(-) create mode 100644 STM32/TSYS_controller/can_process.c create mode 100644 STM32/TSYS_controller/can_process.h diff --git a/STM32/Readme.md b/STM32/Readme.md index 7fb1b0e..ab0fcbf 100644 --- a/STM32/Readme.md +++ b/STM32/Readme.md @@ -1,6 +1,6 @@ -2sensors_logging - source for loggint temperature of 2 sensors -inc - system include files -src4multiplexer - source code for I2C multiplexer (48 channels * 2 sensors) -Tcalc - test code for temperature calculation inside MCU -Tcalc_screen - Tcalc displaying T on OLED screen -TSYS_controller - MAIN controller code (USB, CAN, UART1) +- 2sensors_logging - source for loggint temperature of 2 sensors +- inc - system include files +- src4multiplexer - source code for I2C multiplexer (48 channels * 2 sensors) +- Tcalc - test code for temperature calculation inside MCU +- Tcalc_screen - Tcalc displaying T on OLED screen +- TSYS_controller - MAIN controller code (USB, CAN, UART1) diff --git a/STM32/TSYS_controller/2DO b/STM32/TSYS_controller/2DO index e9245ca..557fd4f 100644 --- a/STM32/TSYS_controller/2DO +++ b/STM32/TSYS_controller/2DO @@ -1,4 +1,3 @@ -- CAN bus: PB8 (Rx), PB9 (Tx) - USB bus: PA11 (DM), PA12 (DP) - ADC inputs: PA0 (V12/4.93), PA1 (V5/2), PA3 (I12 - 1V/A), PA6 (V3.3/2) diff --git a/STM32/TSYS_controller/Makefile b/STM32/TSYS_controller/Makefile index c985cda..45dfc6e 100644 --- a/STM32/TSYS_controller/Makefile +++ b/STM32/TSYS_controller/Makefile @@ -36,6 +36,7 @@ OBJDUMP := $(OPREFIX)-objdump GDB := $(OPREFIX)-gdb STFLASH := $(shell which st-flash) STBOOT := $(shell which stm32flash) +DFUUTIL := $(shell which dfu-util) ############################################################################### # Source files @@ -54,7 +55,7 @@ LIB_DIR := $(INC_DIR)/ld ############################################################################### # C flags -CFLAGS += -O2 -g -MD -D__thumb2__=1 +CFLAGS += -O2 -g -D__thumb2__=1 CFLAGS += -Wall -Wextra -Wshadow -Wimplicit-function-declaration CFLAGS += -Wredundant-decls $(INCLUDE) # -Wmissing-prototypes -Wstrict-prototypes @@ -104,7 +105,7 @@ $(STARTUP): $(INC_DIR)/startup/vector.c $(OBJDIR)/%.o: %.c @echo " CC $<" - $(CC) $(CFLAGS) $(DEFS) $(INCLUDE) $(ARCH_FLAGS) -o $@ -c $< + $(CC) $(CFLAGS) -MD $(DEFS) $(INCLUDE) $(ARCH_FLAGS) -o $@ -c $< #$(OBJDIR)/%.d: %.c $(OBJDIR) # $(CC) -MM -MG $< | sed -e 's,^\([^:]*\)\.o[ ]*:,$(@D)/\1.o $(@D)/\1.d:,' >$@ @@ -130,6 +131,9 @@ clean: $(RM) $(OBJS) $(DEPS) $(ELF) $(HEX) $(LIST) $(OBJDIR)/*.map *.d @rmdir $(OBJDIR) 2>/dev/null || true +dfuboot: $(BIN) + @echo " LOAD $(BIN) THROUGH DFU" + $(DFUUTIL) -a0 -D $(BIN) -s 0x08000000 flash: $(BIN) @echo " FLASH $(BIN)" @@ -142,4 +146,4 @@ boot: $(BIN) gentags: CFLAGS="$(CFLAGS) $(DEFS)" geany -g $(BINARY).c.tags *[hc] 2>/dev/null -.PHONY: clean flash boot gentags +.PHONY: clean flash boot dfuboot gentags diff --git a/STM32/TSYS_controller/Readme.md b/STM32/TSYS_controller/Readme.md index 83cf7db..eac93e7 100644 --- a/STM32/TSYS_controller/Readme.md +++ b/STM32/TSYS_controller/Readme.md @@ -4,12 +4,24 @@ Make regular scan of 8 sensors' pairs. USART speed 115200. Code for ../../kicad/stm32 ### Serial interface commands (ends with '\n'): +- **0...9** - wait measurements of T from Nth controller (0==T for master) +- **A** send everybody to start T measurement +- **B** send dummy CAN messages to broadcast address - **C** show coefficients for all thermosensors -- **D** detect seosors (reseting them) +- **D** send dummy CAN messages to master (0) address +- **E** end temperature scan +- **F** turn sensors off +- **G** get CAN address - **H** switch I2C to high speed (100kHz) +- **I** reinit CAN - **L** switch I2C to low speed (default, 10kHz) -- **R** reset both sensors -- **T** get temperature in degrC +- **O** turn sensors on +- **P** ping everyone over CAN +- **R** reinit I2C +- **S** start temperature scan +- **T** start single temperature measurement +- **V** very low speed +- **Z** get sensors state over CAN ### PINOUT - I2C: PB6 (SCL) & PB7 (SDA) @@ -22,3 +34,27 @@ USART speed 115200. Code for ../../kicad/stm32 - ADC inputs: PA0 (V12/4.93), PA1 (V5/2), PA3 (I12 - 1V/A), PA6 (V3.3/2) - controller CAN address: PA13..PA15 (0..2 bits); 0 - master, other address - slave + +### LEDS +- LED0 (nearest to sensors' connectors) - heartbeat +- LED1 (above LED0) - CAN bus OK + +### CAN protocol +Variable data length: from 1 to 7 bytes. +First byte of every sequence is command mark (0xA5) or data mark (0x5A). + +Commands: +- CMD_PING - send from master to receive answer in data packet if target alive. +- CMD_START_MEASUREMENT - start single temperature measurement. +- CMD_SENSORS_STATE - state of sensors. + +Data format: +- 1 byte - Controller number +- 2 byte - Command received +- 3..7 bytes - data + +Thermal data format: +- 3 byte - Sensor number (10*N + M, where N is multiplexer number, M - number of sensor in pair, i.e. 0,1,10,11,20,21...70,71) +- 4 byte - thermal data H +- 5 byte - thermal data L + diff --git a/STM32/TSYS_controller/can.c b/STM32/TSYS_controller/can.c index 1783389..c09e7ed 100644 --- a/STM32/TSYS_controller/can.c +++ b/STM32/TSYS_controller/can.c @@ -20,16 +20,284 @@ * MA 02110-1301, USA. * */ +#include // memcpy #include "can.h" +#include "hardware.h" +#include "usart.h" -static uint8_t CAN_addr = 0; +// incoming message buffer size +#define CAN_INMESSAGE_SIZE (6) + +extern volatile uint32_t Tms; + +// circular buffer for received messages +static CAN_message messages[CAN_INMESSAGE_SIZE]; +static uint8_t first_free_idx = 0; // index of first empty cell +static int8_t first_nonfree_idx = -1; // index of first data cell + +static uint16_t CANID = 0xFFFF; +uint8_t Controller_address = 0; +static CAN_status can_status = CAN_STOP; + +static void can_process_fifo(uint8_t fifo_num); + +CAN_status CAN_get_status(){ + CAN_status st = can_status; + // give overrun message only once + if(st == CAN_FIFO_OVERRUN) can_status = CAN_READY; + return st; +} + +// 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; + #ifdef EBUG + MSG("1st free: "); usart_putchar('0' + first_free_idx); newline(); + #endif + return 0; +} + +// pop message from buffer +CAN_message *CAN_messagebuf_pop(){ + if(first_nonfree_idx < 0) return NULL; + #ifdef EBUG + MSG("read from idx "); usart_putchar('0' + first_nonfree_idx); newline(); + #endif + CAN_message *msg = &messages[first_nonfree_idx++]; + if(first_nonfree_idx == CAN_INMESSAGE_SIZE) first_nonfree_idx = 0; + if(first_nonfree_idx == first_free_idx){ // buffer is empty - refresh it + first_nonfree_idx = -1; + first_free_idx = 0; + MSG("refresh buffer\n"); + } + return msg; +} // get CAN address data from GPIO pins -void readCANaddr(){ - CAN_addr = READ_CAN_INV_ADDR(); - CAN_addr = ~CAN_addr & 0x7; +void readCANID(){ + uint8_t CAN_addr = READ_CAN_INV_ADDR(); + Controller_address = ~CAN_addr & 0x7; + CANID = (CAN_ID_PREFIX & CAN_ID_MASK) | Controller_address; } -uint8_t getCANaddr(){ - return CAN_addr; +uint16_t getCANID(){ + return CANID; +} + +void CAN_reinit(){ + readCANID(); + CAN->TSR |= CAN_TSR_ABRQ0 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ2; + RCC->APB1RSTR |= RCC_APB1RSTR_CANRST; + RCC->APB1RSTR &= ~RCC_APB1RSTR_CANRST; + CAN_setup(); +} + +void CAN_setup(){ + if(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) Loopback mode, set timing to 100kb/s: BS1 = 4, BS2 = 3, prescaler = 60 */ + /* (5) Leave init mode */ + /* (6) Wait the init mode leaving */ + /* (7) Enter filter init mode, (16-bit + mask, filter 0 for FIFO 0) */ + /* (8) Acivate filter 0 */ + /* (9) Identifier list mode */ + /* (10) Set the Id list */ + /* (12) Leave filter init */ + /* (13) Set error interrupts enable */ + CAN->MCR |= CAN_MCR_INRQ; /* (1) */ + while((CAN->MSR & CAN_MSR_INAK)!=CAN_MSR_INAK) /* (2) */ + { + /* add time out here for a robust application */ + } + CAN->MCR &=~ CAN_MCR_SLEEP; /* (3) */ + CAN->MCR |= CAN_MCR_ABOM; + + CAN->BTR |= 2 << 20 | 3 << 16 | 59 << 0; /* (4) */ + CAN->MCR &=~ CAN_MCR_INRQ; /* (5) */ + while((CAN->MSR & CAN_MSR_INAK)==CAN_MSR_INAK) /* (6) */ + { + /* add time out here for a robust application */ + } + CAN->FMR = CAN_FMR_FINIT; /* (7) */ + CAN->FA1R = CAN_FA1R_FACT0; /* (8) */ + CAN->FM1R = CAN_FM1R_FBM0; /* (9) */ + CAN->sFilterRegister[0].FR1 = CANID << 5 | ((BCAST_ID << 5) << 16); /* (10) */ + + CAN->FMR &=~ CAN_FMR_FINIT; /* (12) */ + 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); + } + if(CAN->ESR & (CAN_ESR_BOFF | CAN_ESR_EPVF | CAN_ESR_EWGF)){ // much errors - restart CAN BUS + LED_off(LED1); + MSG("bus-off, restarting\n"); +#pragma message "TODO: let 2 know main() about problems in CANbus" + // 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(); + } +#ifdef EBUG + static uint32_t esr, msr, tsr; + uint32_t msr_now = CAN->MSR & 0xf; + if(esr != CAN->ESR || msr != msr_now || tsr != CAN->TSR){ + MSG("Timestamp: "); + printu(Tms); + newline(); + } + if((CAN->ESR) != esr){ + usart_putchar(((CAN->ESR & CAN_ESR_BOFF) != 0) + '0'); + esr = CAN->ESR; + MSG("CAN->ESR: "); + printuhex(esr); newline(); + } + if(msr_now != msr){ + msr = msr_now; + MSG("CAN->MSR & 0xf: "); + printuhex(msr); newline(); + } + if(CAN->TSR != tsr){ + tsr = CAN->TSR; + MSG("CAN->TSR: "); + printuhex(tsr); newline(); + } +#endif +} + +CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id){ + LED_on(LED1); // turn ON LED1 at first data sent/receive + uint8_t mailbox = 0; + // check first free mailbox + if(CAN->TSR & (CAN_TSR_TME)){ + mailbox = (CAN->TSR & CAN_TSR_CODE) >> 24; + #ifdef EBUG + MSG("select "); usart_putchar('0'+mailbox); SEND(" mailbox\n"); + #endif + }else{ // no free mailboxes + return CAN_BUSY; + } + CAN_TxMailBox_TypeDef *box = &CAN->sTxMailBox[mailbox]; + uint32_t lb = 0, hb = 0; + switch(len){ + case 8: + hb |= (uint32_t)msg[7] << 24; + case 7: + hb |= (uint32_t)msg[6] << 16; + case 6: + hb |= (uint32_t)msg[5] << 8; + case 5: + hb |= (uint32_t)msg[4]; + case 4: + lb |= (uint32_t)msg[3] << 24; + case 3: + lb |= (uint32_t)msg[2] << 16; + case 2: + lb |= (uint32_t)msg[1] << 8; + default: + lb |= (uint32_t)msg[0]; + } + box->TDLR = lb; + box->TDHR = hb; + box->TDTR = len; + box->TIR = (target_id & 0x7FF) << 21 | CAN_TI0R_TXRQ; + return CAN_OK; +} + +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; + LED_on(LED1); // turn ON LED1 at first data sent/receive + MSG("Receive, RDTR="); + #ifdef EBUG + printuhex(box->RDTR); + newline(); + #endif + // read all + while(*RFxR & CAN_RF0R_FMP0){ // amount of messages pending + // CAN_RDTxR: (16-31) - timestamp, (8-15) - filter match index, (0-3) - data length + /* TODO: check filter match index if more than one ID can receive */ + CAN_message msg; + uint8_t *dat = msg.data; + uint8_t len = box->RDTR & 0x7; + msg.length = len; + if(len){ // message can be without data + uint32_t hb = box->RDHR, lb = box->RDLR; + switch(len){ + case 8: + dat[7] = hb>>24; + case 7: + dat[6] = (hb>>16) & 0xff; + case 6: + dat[5] = (hb>>8) & 0xff; + case 5: + dat[4] = hb & 0xff; + case 4: + dat[3] = lb>>24; + case 3: + dat[2] = (lb>>16) & 0xff; + case 2: + dat[1] = (lb>>8) & 0xff; + case 1: + dat[0] = lb & 0xff; + } + } + if(CAN_messagebuf_push(&msg)) return; // error: buffer is full, try later + *RFxR |= CAN_RF0R_RFOM0; // release fifo for access to next message + } + if(*RFxR & CAN_RF0R_FULL0) *RFxR &= ~CAN_RF0R_FULL0; +} + +void cec_can_isr(){ + if(CAN->RF0R & CAN_RF0R_FOVR0){ // FIFO overrun + CAN->RF0R &= ~CAN_RF0R_FOVR0; + can_status = CAN_FIFO_OVERRUN; + } + if(CAN->RF1R & CAN_RF1R_FOVR1){ + CAN->RF1R &= ~CAN_RF1R_FOVR1; + can_status = CAN_FIFO_OVERRUN; + } + #ifdef EBUG + if(can_status == CAN_FIFO_OVERRUN) MSG("fifo 0 overrun\n"); + #endif + if(CAN->MSR & CAN_MSR_ERRI){ // Error + CAN->MSR &= ~CAN_MSR_ERRI; + // request abort for problem mailbox + if(CAN->TSR & CAN_TSR_TERR0) CAN->TSR |= CAN_TSR_ABRQ0; + if(CAN->TSR & CAN_TSR_TERR1) CAN->TSR |= CAN_TSR_ABRQ1; + if(CAN->TSR & CAN_TSR_TERR2) CAN->TSR |= CAN_TSR_ABRQ2; + } } diff --git a/STM32/TSYS_controller/can.h b/STM32/TSYS_controller/can.h index eb868d1..f347fe9 100644 --- a/STM32/TSYS_controller/can.h +++ b/STM32/TSYS_controller/can.h @@ -26,7 +26,41 @@ #include "hardware.h" -void readCANaddr(); -uint8_t getCANaddr(); +// identifier mask (for ORing with Controller_address +#define CAN_ID_MASK ((uint16_t)0x7F8) +// prefix of identifiers +#define CAN_ID_PREFIX ((uint16_t)0xAAA) +// this is master - Controller_address==0 +#define MASTER_ID (CAN_ID_PREFIX & CAN_ID_MASK) +// broadcasting to every slave +#define BCAST_ID ((uint16_t)0x7F7) +// send dummy message to this ID for testing CAN bus status +#define NOONE_ID ((uint16_t)0x7FF) + +typedef struct{ + uint8_t data[8]; + uint8_t length; +} CAN_message; + +typedef enum{ + CAN_STOP, + CAN_READY, + CAN_BUSY, + CAN_OK, + CAN_FIFO_OVERRUN +} CAN_status; + +CAN_status CAN_get_status(); + +void readCANID(); +uint16_t getCANID(); + +void CAN_reinit(); +void CAN_setup(); + +void can_proc(); +CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id); + +CAN_message *CAN_messagebuf_pop(); #endif // __CAN_H__ diff --git a/STM32/TSYS_controller/can_process.c b/STM32/TSYS_controller/can_process.c new file mode 100644 index 0000000..df1d43d --- /dev/null +++ b/STM32/TSYS_controller/can_process.c @@ -0,0 +1,172 @@ +/* + * 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 "can_process.h" +#include "sensors_manage.h" +#include "can.h" +#include "usart.h" + +extern volatile uint32_t Tms; // timestamp data + +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; +#ifdef EBUG + SEND("got message, len: "); usart_putchar('0' + len); + SEND(", data: "); + uint8_t ctr; + for(ctr = 0; ctr < len; ++ctr){ + printuhex(can_mesg->data[ctr]); + usart_putchar(' '); + } + newline(); +#endif + uint8_t *data = can_mesg->data, b[2]; + b[0] = data[1]; + if(data[0] == COMMAND_MARK){ // process commands + if(len < 2) return; + switch(data[1]){ + case CMD_DUMMY0: + case CMD_DUMMY1: + SEND("DUMMY"); + usart_putchar('0' + (data[1]==CMD_DUMMY0 ? 0 : 1)); + newline(); + break; + case CMD_PING: // pong + can_send_data(b, 1); + break; + case CMD_SENSORS_STATE: + b[1] = sensors_get_state(); + can_send_data(b, 2); + break; + case CMD_START_MEASUREMENT: + sensors_start(); + break; + } + }else if(data[0] == DATA_MARK){ // process received data + if(len < 3) return; + switch(data[2]){ + case CMD_PING: + SEND("PONG"); + usart_putchar('0' + data[1]); + break; + case CMD_SENSORS_STATE: + SEND("SSTATE"); + usart_putchar('0' + data[1]); + usart_putchar('='); + printu(data[3]); + break; + case CMD_START_MEASUREMENT: // temperature + if(len != 6) return; + usart_putchar('T'); + usart_putchar('0' + data[1]); + usart_putchar('_'); + printu(data[3]); + usart_putchar('='); + int16_t t = data[4]<<8 | data[5]; + if(t < 0){ + t = -t; + usart_putchar('-'); + } + printu(t); +#pragma message("TODO: process received T over USB!") + break; + default: + SEND("Unknown data received"); + } + newline(); + } +} + +// try to send messages, wait no more than 100ms +static 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; + } + SEND("Bus busy!\n"); + return CAN_BUSY; +} + + +/** + * Send command over CAN bus (works only if controller number is 0 - master mode) + * @param targetID - target identifier + * @param cmd - command to send + */ +CAN_status can_send_cmd(uint16_t targetID, uint8_t cmd){ + if(Controller_address != 0 && cmd != CMD_DUMMY0 && cmd != CMD_DUMMY1) return CAN_OK; + uint8_t buf[2]; + buf[0] = COMMAND_MARK; + buf[1] = cmd; + return try2send(buf, 2, targetID); +} + +// send data over CAN bus to MASTER_ID (not more than 6 bytes) +CAN_status can_send_data(uint8_t *data, uint8_t len){ + if(len > 6) return CAN_OK; + uint8_t buf[8]; + buf[0] = DATA_MARK; + buf[1] = Controller_address; + int i; + for(i = 0; i < len; ++i) buf[i+2] = *data++; + return try2send(buf, len+2, MASTER_ID); +} + +/** + * send temperature data over CAN bus once per call + * @return next number or -1 if all data sent + */ +int8_t send_temperatures(int8_t N){ + if(N < 0 || Controller_address == 0) return -1; + int a, p; + uint8_t can_data[4]; + int8_t retn = N; + can_data[0] = CMD_START_MEASUREMENT; + a = N / 10; + p = N - a*10; + if(p == 2){ // next sensor + if(++a > MUL_MAX_ADDRESS) return -1; + p = 0; + } + do{ + if(!(sens_present[p] & (1< MUL_MAX_ADDRESS) return -1; // done + retn = a*10 + p; // current temperature sensor number + can_data[1] = a*10 + p; + //char b[] = {'T', a+'0', p+'0', '=', '+'}; + int16_t t = Temperatures[a][p]; + can_data[2] = t>>8; // H byte + can_data[3] = t&0xff; // L byte + if(CAN_OK == can_send_data(can_data, 4)){ // OK, calculate next address + ++retn; + } + return retn; +} diff --git a/STM32/TSYS_controller/can_process.h b/STM32/TSYS_controller/can_process.h new file mode 100644 index 0000000..4917e8a --- /dev/null +++ b/STM32/TSYS_controller/can_process.h @@ -0,0 +1,45 @@ +/* + * 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) +// mark first byte if command sent +#define COMMAND_MARK (0xA5) +// mark first byte if data sent +#define DATA_MARK (0x5A) + +// 8-bit commands sent by master +typedef enum{ + CMD_PING, // request for PONG cmd + CMD_START_MEASUREMENT, // start thermal measurement + CMD_SENSORS_STATE, // reply data with sensors state + // dummy commands for test purposes + CMD_DUMMY0 = 0xDA, + CMD_DUMMY1 = 0xAD +} CAN_commands; + +void can_messages_proc(); +CAN_status can_send_cmd(uint16_t targetID, uint8_t cmd); +CAN_status can_send_data(uint8_t *data, uint8_t len); +int8_t send_temperatures(int8_t N); diff --git a/STM32/TSYS_controller/hardware.h b/STM32/TSYS_controller/hardware.h index fa5913b..e795a42 100644 --- a/STM32/TSYS_controller/hardware.h +++ b/STM32/TSYS_controller/hardware.h @@ -55,12 +55,14 @@ #define LED1_pin LED0_pin #endif #define LED_blink(x) pin_toggle(x ## _port, x ## _pin) +#define LED_on(x) pin_clear(x ## _port, x ## _pin) +#define LED_off(x) pin_set(x ## _port, x ## _pin) // set active channel number #define MUL_ADDRESS(x) do{GPIOB->BSRR = (0x7 << 16) | (x);}while(0) // address from 0 to 7 // WARNING!!! In current case all variables for sensors counting are uint8_t, so if -// MUL_MAX_ADDRESS would be greater than 7 you need to edit sensors_manage.c +// MUL_MAX_ADDRESS would be greater than 7 you need to edit all codes!!!11111111111111111111 #define MUL_MAX_ADDRESS (7) // turn multiplexer on/off (PB12 -> 1/0) #define MUL_ON() pin_clear(GPIOB, (1<<12)) @@ -74,6 +76,7 @@ // CAN address - PA13..PA15 #define READ_CAN_INV_ADDR() ((GPIOA->IDR & (0x7<<13))>>13) +extern uint8_t Controller_address; typedef enum{ VERYLOW_SPEED, diff --git a/STM32/TSYS_controller/i2c.c b/STM32/TSYS_controller/i2c.c index c5f02cb..57deba5 100644 --- a/STM32/TSYS_controller/i2c.c +++ b/STM32/TSYS_controller/i2c.c @@ -54,12 +54,12 @@ uint8_t write_i2c(uint8_t addr, uint8_t data){ cntr = Tms; I2C1->ICR = 0x3f38; // clear all errors while(I2C1->ISR & I2C_ISR_BUSY) if(Tms - cntr > I2C_TIMEOUT){ - MSG("always busy\n"); + //MSG("always busy\n"); return 0; // check busy } cntr = Tms; while(I2C1->CR2 & I2C_CR2_START) if(Tms - cntr > I2C_TIMEOUT){ - MSG("always start\n"); + //MSG("always start\n"); return 0; // check start } //I2C1->ICR = 0x3f38; // clear all errors @@ -71,12 +71,12 @@ uint8_t write_i2c(uint8_t addr, uint8_t data){ if(I2C1->ISR & I2C_ISR_NACKF){ I2C1->ICR |= I2C_ICR_NACKCF; //I2C1->ICR = 0x3f38; - MSG("NACK\n"); + //MSG("NACK\n"); return 0; } if(Tms - cntr > I2C_TIMEOUT){ //I2C1->ICR = 0x3f38; - MSG("Timeout\n"); + //MSG("Timeout\n"); return 0; } } @@ -93,14 +93,14 @@ uint8_t write_i2c(uint8_t addr, uint8_t data){ uint8_t read_i2c(uint8_t addr, uint32_t *data, uint8_t nbytes){ uint32_t result = 0; cntr = Tms; - MSG("read_i2c\n"); + //MSG("read_i2c\n"); while(I2C1->ISR & I2C_ISR_BUSY) if(Tms - cntr > I2C_TIMEOUT){ - MSG("always busy\n"); + //MSG("always busy\n"); return 0; // check busy } cntr = Tms; while(I2C1->CR2 & I2C_CR2_START) if(Tms - cntr > I2C_TIMEOUT){ - MSG("always start\n"); + //MSG("always start\n"); return 0; // check start } // I2C1->ICR = 0x3f38; // clear all errors @@ -114,12 +114,12 @@ uint8_t read_i2c(uint8_t addr, uint32_t *data, uint8_t nbytes){ if(I2C1->ISR & I2C_ISR_NACKF){ I2C1->ICR |= I2C_ICR_NACKCF; //I2C1->ICR = 0x3f38; - MSG("NACK\n"); + //MSG("NACK\n"); return 0; } if(Tms - cntr > I2C_TIMEOUT){ //I2C1->ICR = 0x3f38; - MSG("Timeout\n"); + //MSG("Timeout\n"); return 0; } } diff --git a/STM32/TSYS_controller/main.c b/STM32/TSYS_controller/main.c index e94b9c2..1d8686d 100644 --- a/STM32/TSYS_controller/main.c +++ b/STM32/TSYS_controller/main.c @@ -24,6 +24,7 @@ #include "i2c.h" #include "sensors_manage.h" #include "can.h" +#include "can_process.h" #pragma message("USARTNUM=" STR(USARTNUM)) #pragma message("I2CPINS=" STR(I2CPINS)) @@ -61,10 +62,17 @@ void iwdg_setup(){ IWDG->KR = IWDG_REFRESH; /* (6) */ } +void CANsend(uint16_t targetID, uint8_t cmd, char echo){ + if(CAN_OK == can_send_cmd(targetID, cmd)){ + usart_putchar(echo); + newline(); + } +} + int main(void){ uint32_t lastT = 0, lastS = 0; - int16_t L = 0; - uint8_t scan = 0, gotmeasurement = 0; + int16_t L = 0, ID; + uint8_t gotmeasurement = 0; char *txt; sysreset(); SysTick_Config(6000, 1); @@ -72,28 +80,43 @@ int main(void){ usart_setup(); i2c_setup(LOW_SPEED); iwdg_setup(); - readCANaddr(); + CAN_setup(); SEND("Greetings! My address is "); - printu(getCANaddr()); + printuhex(getCANID()); newline(); + if(RCC->CSR & RCC_CSR_IWDGRSTF){ // watchdog reset occured + SEND("WDGRESET=1\n"); + } + if(RCC->CSR & RCC_CSR_SFTRSTF){ // software reset occured + SEND("SOFTRESET=1\n"); + } + RCC->CSR |= RCC_CSR_RMVF; // remove reset flags + while (1){ IWDG->KR = IWDG_REFRESH; // refresh watchdog if(lastT > Tms || Tms - lastT > 499){ LED_blink(LED0); lastT = Tms; + // send dummy command to noone to test CAN bus + can_send_cmd(NOONE_ID, CMD_DUMMY0); } if(lastS > Tms || Tms - lastS > 5){ // run sensors proc. once per 5ms sensors_process(); lastS = Tms; } - if(scan){ + can_proc(); + if(CAN_get_status() == CAN_FIFO_OVERRUN){ + SEND("CAN bus fifo overrun occured!\n"); + } + can_messages_proc(); + //if(sensors_scan_mode){ if(SENS_SLEEPING == sensors_get_state()){ // show temperature @ each sleeping occurence if(!gotmeasurement){ //SEND("\nTIME="); - printu(Tms); - usart_putchar('\t'); + //printu(Tms); + //usart_putchar('\t'); //newline(); gotmeasurement = 1; showtemperature(); @@ -101,55 +124,81 @@ int main(void){ }else{ gotmeasurement = 0; } - } + //} if(usartrx()){ // usart1 received data, store in in buffer L = usart_getline(&txt); char _1st = txt[0]; if(L == 2 && txt[1] == '\n'){ L = 0; - switch(_1st){ + if(_1st > '0' && _1st < '8'){ + ID = (CAN_ID_PREFIX & CAN_ID_MASK) | (_1st - '0'); + CANsend(ID, CMD_START_MEASUREMENT, _1st); + }else switch(_1st){ + case 'A': + CANsend(BCAST_ID, CMD_START_MEASUREMENT, _1st); + if(!sensors_scan_mode) sensors_start(); + break; + case 'B': + CANsend(BCAST_ID, CMD_DUMMY0, _1st); + break; case 'C': // 'C' - show coefficients showcoeffs(); break; - case 'O': - sensors_on(); + case 'D': + CANsend(MASTER_ID, CMD_DUMMY1, _1st); + break; + case 'E': + SEND("End scan mode\n"); + sensors_scan_mode = 0; break; case 'F': sensors_off(); break; - case 'T': // 'T' - get temperature - showtemperature(); - break; - case 'R': - i2c_setup(CURRENT_SPEED); - SEND("Reinit I2C\n"); - break; - case 'V': - i2c_setup(VERYLOW_SPEED); - SEND("Very low speed\n"); - break; - case 'L': - i2c_setup(LOW_SPEED); - SEND("Low speed\n"); + case 'G': + SEND("Can address: "); + printuhex(getCANID()); + newline(); break; case 'H': i2c_setup(HIGH_SPEED); SEND("High speed\n"); break; - case 'G': + case 'I': + CAN_reinit(); SEND("Can address: "); - printu(getCANaddr()); + printuhex(getCANID()); newline(); break; + case 'L': + i2c_setup(LOW_SPEED); + SEND("Low speed\n"); + break; + case 'O': + sensors_on(); + break; + case 'P': + CANsend(BCAST_ID, CMD_PING, _1st); + break; + case 'R': + i2c_setup(CURRENT_SPEED); + SEND("Reinit I2C\n"); + break; case 'S': SEND("Start scan mode\n"); - scan = 1; + sensors_scan_mode = 1; break; - case 'P': - SEND("End scan mode\n"); - scan = 0; + case '0': + case 'T': // 'T' - get temperature + if(!sensors_scan_mode) sensors_start(); break; -#ifdef EBUG + case 'V': + i2c_setup(VERYLOW_SPEED); + SEND("Very low speed\n"); + break; + case 'Z': + CANsend(BCAST_ID, CMD_SENSORS_STATE, _1st); + break; +#if 0 case 'd': case 'g': case 't': @@ -161,24 +210,32 @@ int main(void){ break; #endif default: // help - SEND("'C' - show coefficients\n" - "'G' - get CAN address\n" - "'F' - turn oFf sensors\n" - "'H' - high speed\n" - "'L' - low speed\n" - "'O' - turn On sensors\n" - "'P' - stoP themperature scan\n" - "'R' - reinit I2C\n" - "'S' - Start themperature scan\n" - "'T' - get raw temperature\n" - "'V' - very low speed\n" -#ifdef EBUG + SEND( + "0..7 - start measurement on given controller\n" + "A - start measurement on all controllers\n" + "B - send broadcast CAN dummy message\n" + "C - show coefficients\n" + "D - send CAN dummy message to master\n" + "E - end themperature scan\n" + "F - turn oFf sensors\n" + "G - get CAN address\n" + "H - high speed\n" + "I - reinit CAN\n" + "L - low speed\n" + "O - turn On sensors\n" + "P - ping everyone over CAN\n" + "R - reinit I2C\n" + "S - Start themperature scan\n" + "T - start temperature measurement\n" + "V - very low speed\n" + "Z - get sensors state over CAN\n" +#if 0 "\t\tTEST OPTIONS\n" - "'d' - discovery\n" - "'g' - get coeff\n" - "'t' - measure temper\n" - "'s' - show temper measured\n" - "'p' - sensors_process()\n" + "d - discovery\n" + "g - get coeff\n" + "t - measure temper\n" + "s - show temper measured\n" + "p - sensors_process()\n" #endif ); break; diff --git a/STM32/TSYS_controller/sensors_manage.c b/STM32/TSYS_controller/sensors_manage.c index 36cbc41..ba0ca72 100644 --- a/STM32/TSYS_controller/sensors_manage.c +++ b/STM32/TSYS_controller/sensors_manage.c @@ -21,22 +21,24 @@ * */ #include "sensors_manage.h" +#include "can_process.h" #include "i2c.h" #include "usart.h" extern volatile uint32_t Tms; +uint8_t sensors_scan_mode = 0; // infinite scan mode static uint32_t lastSensT = 0; static SensorsState Sstate = SENS_OFF; // turn on sensors only by request -static uint8_t curr_mul_addr = 0; // current sensors pair address @ multiplexer -static uint8_t overcurnt_ctr = 0; // if this counter > 32 go to OFF state -static uint8_t sens_present[2] = {0,0}; // bit flag: Nth bit == 1 if sensor[s] on given channel found +static uint8_t curr_mul_addr = 0; // current sensors pair address @ multiplexer +static uint8_t overcurnt_ctr = 0; // if this counter > 32 go to OFF state +uint8_t sens_present[2] = {0,0}; // bit flag: Nth bit == 1 if sensor[s] on given channel found static uint8_t Nsens_present = 0; // total amount of sensors found static uint8_t Ntemp_measured = 0; // total amount of themperatures measured // 8 - amount of pairs, 2 - amount in pair, 5 - amount of Coef. static uint16_t coefficients[MUL_MAX_ADDRESS+1][2][5]; // Coefficients for given sensors // measured temperatures * 100 -static int16_t Temperatures[MUL_MAX_ADDRESS+1][2]; +int16_t Temperatures[MUL_MAX_ADDRESS+1][2]; // pair addresses static const uint8_t Taddr[2] = {TSYS01_ADDR0, TSYS01_ADDR1}; @@ -96,6 +98,25 @@ void sensors_on(){ } } +/** + * start measurement if sensors are sleeping, + * turn ON if they were OFF + * do nothing if measurement processing + */ +void sensors_start(){ + if(sensors_scan_mode) return; + switch(Sstate){ + case SENS_SLEEPING: + Sstate = SENS_START_MSRMNT; + break; + case SENS_OFF: + sensors_on(); + break; + default: + break; + } +} + /* / count bits in byte static uint8_t bitCount(uint8_t B){ uint8_t ctr = 0; @@ -146,7 +167,7 @@ static uint8_t resetproc(){ static uint8_t getcoefsproc(){ uint8_t i, j; const uint8_t regs[5] = {0xAA, 0xA8, 0xA6, 0xA4, 0xA2}; // commands for coefficients -#ifdef EBUG +#if 0 MSG("sens_present[0]="); printu(sens_present[0]); SEND(", sens_present[1]="); @@ -157,7 +178,7 @@ newline(); if(!(sens_present[i] & (1<reset\n"); +//MSG("init->reset\n"); i2c_setup(CURRENT_SPEED); Sstate = SENS_RESETING; lastSensT = Tms; @@ -358,10 +379,10 @@ MSG("init->reset\n"); if(sensors_scan(resetproc)){ count_sensors(); // get total amount of sensors if(Nsens_present){ -MSG("reset->getcoeff\n"); +//MSG("reset->getcoeff\n"); Sstate = SENS_GET_COEFFS; }else{ // no sensors found -MSG("reset->off\n"); +//MSG("reset->off\n"); sensors_off(); } } @@ -369,8 +390,8 @@ MSG("reset->off\n"); break; case SENS_GET_COEFFS: // get coefficients if(sensors_scan(getcoefsproc)){ -MSG("got coeffs for "); -#ifdef EBUG +//MSG("got coeffs for "); +#if 0 printu(Nsens_present); SEND(" sensors ->start\n"); #endif @@ -380,23 +401,29 @@ SEND(" sensors ->start\n"); case SENS_START_MSRMNT: // send all sensors command to start measurements if(sensors_scan(msrtempproc)){ lastSensT = Tms; -MSG("->wait\n"); +//MSG("->wait\n"); Sstate = SENS_WAITING; Ntemp_measured = 0; // reset value of good measurements } break; case SENS_WAITING: // wait for end of conversion if(Tms - lastSensT > CONV_TIME){ -MSG("->gather\n"); +//MSG("->gather\n"); Sstate = SENS_GATHERING; } break; case SENS_GATHERING: // scan all sensors, get thermal data & calculate temperature if(sensors_scan(gettempproc)){ lastSensT = Tms; - if(Nsens_present != Ntemp_measured) i2c_setup(CURRENT_SPEED); - Sstate = SENS_SLEEPING; -MSG("->sleep\n"); + if(Nsens_present != Ntemp_measured){ + i2c_setup(CURRENT_SPEED); + sensors_on(); + } + else{ + NsentOverCAN = 0; + Sstate = SENS_SLEEPING; + } +//MSG("->sleep\n"); /* if(Nsens_present == Ntemp_measured){ // All OK, amount of T == amount of sensors MSG("->sleep\n"); @@ -409,13 +436,16 @@ MSG("gather error ->start\n"); } break; case SENS_SLEEPING: // wait for `SLEEP_TIME` till next measurements - if(Tms - lastSensT > SLEEP_TIME){ -MSG("sleep->start\n"); - Sstate = SENS_START_MSRMNT; + NsentOverCAN = send_temperatures(NsentOverCAN); // call sending T process + if(sensors_scan_mode){ // sleep until next measurement start + if(Tms - lastSensT > SLEEP_TIME){ + //MSG("sleep->start\n"); + Sstate = SENS_START_MSRMNT; + } } break; case SENS_OVERCURNT: // try to reinit all after overcurrent -MSG("try to turn on after overcurrent\n"); +//MSG("try to turn on after overcurrent\n"); sensors_on(); break; default: // do nothing @@ -423,7 +453,7 @@ MSG("try to turn on after overcurrent\n"); } } -#ifdef EBUG +#if 0 void senstest(char cmd){ MUL_OFF(); SENSORS_ON(); diff --git a/STM32/TSYS_controller/sensors_manage.h b/STM32/TSYS_controller/sensors_manage.h index c699783..358343f 100644 --- a/STM32/TSYS_controller/sensors_manage.h +++ b/STM32/TSYS_controller/sensors_manage.h @@ -35,6 +35,10 @@ // no sensor on given channel #define NO_SENSOR (-31000) +extern uint8_t sensors_scan_mode; +extern int16_t Temperatures[MUL_MAX_ADDRESS+1][2]; +extern uint8_t sens_present[2]; + typedef enum{ SENS_INITING // power on ,SENS_RESETING // discovery sensors resetting them @@ -53,6 +57,7 @@ void sensors_process(); void sensors_off(); void sensors_on(); +void sensors_start(); void showcoeffs(); void showtemperature(); diff --git a/STM32/TSYS_controller/tsys01.bin b/STM32/TSYS_controller/tsys01.bin index 52a2d04c432a7a026926630b16f3062310f8c5df..9e77c04599697d1ac4e12e1b7b5b8ff870acb8f9 100755 GIT binary patch delta 5862 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 delta 3021 zcmah~Yj6|S6+TxFyq0Y&FgCUX?rLRQ0%6C1!z(lhi7c{KJZdNun*Or2XSbEISh0HBR?v4lVK$__%8h0_}w=DKgJ|r z{+s*lAcy|=AguA`iDY)3Ke)7q$NE@eQM<46Yx(8;6Z~t!jc$|pn#bTa`D?}J&S;#q zev|mBN8>c%_)2=L6@PRSA# zFkqY$+&b|ktwBTDR5U8kBbnKdmnEQ`Gu*d!zmWu5#s0c=tJY2oQ*hxt|fcJy_K$6fl~`{II&Zq%|DPd zSZ1QCCav18Xp!5K%(9dt=Sg!L(VQeU;Qy(_dPRf!7SxxaeqLH%qmWK;fZV3oMNpY! zCJU;73ql42o=A-f7&Xr9w^K|i^&pu_4Wv@3p45z_bUkBwl{gKU`?yCz2Ob8;LY&`0 zTtIw+cpGsLaRSkfIE|1FFjeEf8~}S}tk_bC{r+M=dY|EZUk%+=ZeWZ{h)M@AYWI6Q zbeH+`>7DZ1LAq0{E9Qkj{n-%b)27+uX_i>;u*DWAfwHN%Q$T%dKw6kN#dsWZs4@$c zl|5ac9vhUz%#yNgX%A3;JqWDs4+nYmd=FoR*=W{9Kv z6)l(fI+gbhNW})93DjQ>d3d6}oC0p1K-Bj5Tw$JXtZ% z4F+{pQWMp75_Lmdde2~Iy>U254(SdPH5X%;Fvj9IL~$|Ha@+wqNojl*_kCIzEy{?X zZMpq?DpiHDyf2k<_C84UboLMid4S-e?*3bk|40111E9nS(Eq0#X-8IFKK3}>RJuq+ zC=Ahyg-F-3tb|A;du=|APP1eqsLdxh5@|>FHshypuuqjW9C_V?-(8ZBZf7sd87+tw zQzbo_W6^XZq)5*8f*&Nn9*>bKd&e#8cgcX}Q9NAB|@pMlb>`0xU)~;YC9^f z(naY_&~0l@kViFhH06ev&U%z5b3a?cJW?u?u=O41az4sKX&qm~*F9-+-H2tRlYJg1 z_Af@{Ybf87uPfty1!>*KIFHNclscEWtDL19>rVWyc#7ijGs@@(<>1HAmAQck;RpH= zHA1l4)HpF?(xnJjL!$K&E_~2hqr0kKRvoR+3X$1Yx>&2^>RfCH*14*^%yr(Sjr1}bzV81K71e1vHBSJ3hN7SW}=~4fELTj}KuPY0L$Gm27 zqS$H5b^PPJ*5E9`6ns~y5GqDoD!r2H{AC?Fol`2% z=~Hy-mLDjkLfME#f~x_^^~Pl=og&ygQ-i6#zoX5oa%pw3#}Lv7h0sJzp4%+VG)@lZ z%9`2M;DPi_RG%OiH5aoZ{J=4oIjlrDy)fLF;l@PkGtjD4>ER#lKkVnN>A+-;1BPBK zy$ITK+V9VFc(G&wyvqRdL;diPJ!rkEH#KHhYqF#QH}PUeag*Of{fDy^hM`=%pUI1(8+tk#l`tW_VZD>eEd(upD#EB$lPeqE}s zpkG>PD&c5@d+;RmVA1K3%HP1*UzrY&ta1GsYza*3lXspa#Y-7Y#BtVJR-3cD3YYjr z?Jz1(zKHUIuW?j2?rU@0Hq5yZdlSm1Q2yu0{Ek-IS5+LY2{bk}wz1W-+y+<^XnBU+ z-n@%#4F&?64B#6R!PB@!9Od2hO>F(9O)Y`e)&(p8tZJ)oX=7U(klxX}DPTYfo@m -1; --j){ + uint8_t half = (*ptr >> (4*j)) & 0x0f; + if(half < 10) usart_putchar(half + '0'); + else usart_putchar(half - 10 + 'a'); + } + } +} + #if USARTNUM == 2 void dma1_channel4_5_isr(){ if(DMA1->ISR & DMA_ISR_TCIF4){ // Tx diff --git a/STM32/TSYS_controller/usart.h b/STM32/TSYS_controller/usart.h index f1d1d50..ae2da2e 100644 --- a/STM32/TSYS_controller/usart.h +++ b/STM32/TSYS_controller/usart.h @@ -56,5 +56,6 @@ TXstatus usart_send_blocking(const char *str, int len); void newline(); void usart_putchar(const char ch); void printu(uint32_t val); +void printuhex(uint32_t val); #endif // __USART_H__