fixed some bugs in canUART for F103, add some features to usbcan_ringbuffer for F0

This commit is contained in:
Edward Emelianov 2022-12-05 18:05:35 +03:00
parent cfff079dba
commit 59fb731725
24 changed files with 379 additions and 90 deletions

View File

@ -8,6 +8,7 @@ FAMILY ?= F0
MCU ?= F042x6 MCU ?= F042x6
# change this linking script depending on particular MCU model, # change this linking script depending on particular MCU model,
LDSCRIPT ?= stm32f042x6.ld LDSCRIPT ?= stm32f042x6.ld
#DEFS = -DEBUG
# autoincremental version & build date # autoincremental version & build date
VERSION_FILE = version.inc VERSION_FILE = version.inc

View File

@ -21,17 +21,14 @@
#include "proto.h" #include "proto.h"
#include "usb.h" #include "usb.h"
#include <string.h> // memcpy
// circular buffer for received messages // circular buffer for received messages
static CAN_message messages[CAN_INMESSAGE_SIZE]; static CAN_message messages[CAN_INMESSAGE_SIZE];
static uint8_t first_free_idx = 0; // index of first empty cell 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 int8_t first_nonfree_idx = -1; // index of first data cell
static uint16_t oldspeed = 100; // speed of last init static uint16_t oldspeed = 100; // speed of last init
uint32_t floodT = FLOOD_PERIOD_MS-1; // flood period in ms
#ifdef EBUG
static uint32_t last_err_code = 0; static uint32_t last_err_code = 0;
#endif
static CAN_status can_status = CAN_STOP; static CAN_status can_status = CAN_STOP;
static void can_process_fifo(uint8_t fifo_num); static void can_process_fifo(uint8_t fifo_num);
@ -65,7 +62,7 @@ static int CAN_messagebuf_push(CAN_message *msg){
return 1; // no free space return 1; // no free space
} }
if(first_nonfree_idx < 0) first_nonfree_idx = 0; // first message in empty buffer if(first_nonfree_idx < 0) first_nonfree_idx = 0; // first message in empty buffer
memcpy(&messages[first_free_idx++], msg, sizeof(CAN_message)); messages[first_free_idx++] = *msg;
// need to roll? // need to roll?
if(first_free_idx == CAN_INMESSAGE_SIZE) first_free_idx = 0; if(first_free_idx == CAN_INMESSAGE_SIZE) first_free_idx = 0;
return 0; return 0;
@ -146,9 +143,7 @@ void CAN_setup(uint16_t speed){
/* (13) Set error interrupts enable */ /* (13) Set error interrupts enable */
CAN->MCR |= CAN_MCR_INRQ; /* (1) */ CAN->MCR |= CAN_MCR_INRQ; /* (1) */
while((CAN->MSR & CAN_MSR_INAK)!=CAN_MSR_INAK) /* (2) */ while((CAN->MSR & CAN_MSR_INAK)!=CAN_MSR_INAK) /* (2) */
{
if(--tmout == 0) break; if(--tmout == 0) break;
}
CAN->MCR &=~ CAN_MCR_SLEEP; /* (3) */ CAN->MCR &=~ CAN_MCR_SLEEP; /* (3) */
CAN->MCR |= CAN_MCR_ABOM; /* allow automatically bus-off */ CAN->MCR |= CAN_MCR_ABOM; /* allow automatically bus-off */
@ -174,6 +169,36 @@ void CAN_setup(uint16_t speed){
can_status = CAN_READY; can_status = CAN_READY;
} }
void printCANerr(){
if(!last_err_code) last_err_code = CAN->ESR;
if(!last_err_code){
USB_sendstr("No errors\n");
return;
}
USB_sendstr("Receive error counter: ");
printu((last_err_code & CAN_ESR_REC)>>24);
USB_sendstr("\nTransmit error counter: ");
printu((last_err_code & CAN_ESR_TEC)>>16);
USB_sendstr("\nLast error code: ");
int lec = (last_err_code & 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;
}
USB_sendstr(errmsg); USB_sendstr(" error\n");
if(last_err_code & CAN_ESR_BOFF) USB_sendstr("Bus off ");
if(last_err_code & CAN_ESR_EPVF) USB_sendstr("Passive error limit ");
if(last_err_code & CAN_ESR_EWGF) USB_sendstr("Error counter limit");
last_err_code = 0;
USB_putbyte('\n');
}
void can_proc(){ void can_proc(){
#ifdef EBUG #ifdef EBUG
if(last_err_code){ if(last_err_code){
@ -193,27 +218,7 @@ void can_proc(){
IWDG->KR = IWDG_REFRESH; IWDG->KR = IWDG_REFRESH;
if(CAN->ESR & (CAN_ESR_BOFF | CAN_ESR_EPVF | CAN_ESR_EWGF)){ // much errors - restart CAN BUS if(CAN->ESR & (CAN_ESR_BOFF | CAN_ESR_EPVF | CAN_ESR_EWGF)){ // much errors - restart CAN BUS
USB_sendstr("\nToo much errors, restarting CAN!\n"); USB_sendstr("\nToo much errors, restarting CAN!\n");
USB_sendstr("Receive error counter: "); printCANerr();
printu((CAN->ESR & CAN_ESR_REC)>>24);
USB_sendstr("\nTransmit error counter: ");
printu((CAN->ESR & CAN_ESR_TEC)>>16);
USB_sendstr("\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;
}
USB_sendstr(errmsg); USB_sendstr(" error\n");
if(CAN->ESR & CAN_ESR_BOFF) USB_sendstr("Bus off ");
if(CAN->ESR & CAN_ESR_EPVF) USB_sendstr("Passive error limit ");
if(CAN->ESR & CAN_ESR_EWGF) USB_sendstr("Error counter limit");
USB_putbyte('\n');
// request abort for all mailboxes // request abort for all mailboxes
CAN->TSR |= CAN_TSR_ABRQ0 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ2; CAN->TSR |= CAN_TSR_ABRQ0 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ2;
// reset CAN bus // reset CAN bus
@ -222,7 +227,7 @@ void can_proc(){
CAN_setup(0); CAN_setup(0);
} }
static uint32_t lastFloodTime = 0; static uint32_t lastFloodTime = 0;
if(flood_msg && (Tms - lastFloodTime) > (FLOOD_PERIOD_MS-1)){ // flood every ~5ms if(flood_msg && (Tms - lastFloodTime) > (floodT)){ // flood every ~5ms
lastFloodTime = Tms; lastFloodTime = Tms;
can_send(flood_msg->data, flood_msg->length, flood_msg->ID); can_send(flood_msg->data, flood_msg->length, flood_msg->ID);
} }
@ -285,7 +290,21 @@ CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id){
void set_flood(CAN_message *msg){ void set_flood(CAN_message *msg){
if(!msg) flood_msg = NULL; if(!msg) flood_msg = NULL;
else{ else{
memcpy(&loc_flood_msg, msg, sizeof(CAN_message)); #ifdef EBUG
USB_sendstr("flood msg: #");
printuhex(msg->ID);
for(uint8_t ctr = 0; ctr < msg->length; ++ctr){
USB_putbyte(' ');
printuhex(msg->data[ctr]);
}
USB_putbyte('\n');
#endif
// I meet strange problems with `loc_flood_msg = *msg` and system memcpy, so..
loc_flood_msg.ID = msg->ID;
loc_flood_msg.length = msg->length;
*((uint32_t*)loc_flood_msg.data) = *((uint32_t*)msg->data);
if(loc_flood_msg.length > 4)
*((uint32_t*)&loc_flood_msg.data[4]) = *((uint32_t*)&msg->data[4]);
flood_msg = &loc_flood_msg; flood_msg = &loc_flood_msg;
} }
} }
@ -364,3 +383,4 @@ void cec_can_isr(){
#endif #endif
} }
} }

View File

@ -18,7 +18,7 @@
#pragma once #pragma once
#include "hardware.h" #include <stdint.h>
// amount of filter banks in STM32F0 // amount of filter banks in STM32F0
#define STM32F0FBANKNO 28 #define STM32F0FBANKNO 28
@ -28,6 +28,8 @@
// incoming message buffer size // incoming message buffer size
#define CAN_INMESSAGE_SIZE (8) #define CAN_INMESSAGE_SIZE (8)
extern uint32_t floodT;
// CAN message // CAN message
typedef struct{ typedef struct{
uint8_t data[8]; // up to 8 bytes of data uint8_t data[8]; // up to 8 bytes of data
@ -50,6 +52,7 @@ void CAN_setup(uint16_t speed);
CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id); CAN_status can_send(uint8_t *msg, uint8_t len, uint16_t target_id);
void can_proc(); void can_proc();
void printCANerr();
CAN_message *CAN_messagebuf_pop(); CAN_message *CAN_messagebuf_pop();

View File

@ -68,7 +68,7 @@ int main(void){
USB_sendstr(" #"); USB_sendstr(" #");
printuhex(can_mesg->ID); printuhex(can_mesg->ID);
for(uint8_t ctr = 0; ctr < len; ++ctr){ for(uint8_t ctr = 0; ctr < len; ++ctr){
USB_putbyte('\n'); USB_putbyte(' ');
printuhex(can_mesg->data[ctr]); printuhex(can_mesg->data[ctr]);
} }
USB_putbyte('\n'); USB_putbyte('\n');

View File

@ -137,6 +137,7 @@ static char *getbin(const char *buf, uint32_t *N){
char *getnum(const char *txt, uint32_t *N){ char *getnum(const char *txt, uint32_t *N){
char *nxt = NULL; char *nxt = NULL;
char *s = omit_spaces(txt); char *s = omit_spaces(txt);
if(!*s) return (char*)txt;
if(*s == '0'){ // hex, oct or 0 if(*s == '0'){ // hex, oct or 0
if(s[1] == 'x' || s[1] == 'X'){ // hex if(s[1] == 'x' || s[1] == 'X'){ // hex
nxt = gethex(s+2, N); nxt = gethex(s+2, N);
@ -166,7 +167,6 @@ static CAN_message *parseCANmsg(char *txt){
int ctr = -1; int ctr = -1;
canmsg.ID = 0xffff; canmsg.ID = 0xffff;
do{ do{
txt = omit_spaces(txt);
n = getnum(txt, &N); n = getnum(txt, &N);
if(txt == n) break; if(txt == n) break;
txt = n; txt = n;
@ -200,16 +200,19 @@ static CAN_message *parseCANmsg(char *txt){
// USB_sendstr command, format: ID (hex/bin/dec) data bytes (up to 8 bytes, space-delimeted) // USB_sendstr command, format: ID (hex/bin/dec) data bytes (up to 8 bytes, space-delimeted)
TRUE_INLINE void USB_sendstrCANcommand(char *txt){ TRUE_INLINE void USB_sendstrCANcommand(char *txt){
if(CAN->MSR & CAN_MSR_INAK){
USB_sendstr("CAN bus is off, try to restart it\n");
return;
}
CAN_message *msg = parseCANmsg(txt); CAN_message *msg = parseCANmsg(txt);
if(!msg) return; if(!msg) return;
uint32_t N = 1000000; uint32_t N = 5;
while(CAN_BUSY == can_send(msg->data, msg->length, msg->ID)){ while(CAN_BUSY == can_send(msg->data, msg->length, msg->ID)){
if(--N == 0) break; if(--N == 0) break;
} }
} }
TRUE_INLINE void CANini(char *txt){ TRUE_INLINE void CANini(char *txt){
txt = omit_spaces(txt);
uint32_t N; uint32_t N;
char *n = getnum(txt, &N); char *n = getnum(txt, &N);
if(txt == n){ if(txt == n){
@ -318,6 +321,17 @@ TRUE_INLINE void list_filters(){
} }
} }
TRUE_INLINE void setfloodt(char *s){
uint32_t N;
s = omit_spaces(s);
char *n = getnum(s, &N);
if(s == n || N == 0){
USB_sendstr("t="); printu(floodT); USB_putbyte('\n');
return;
}
floodT = N - 1;
}
/** /**
* @brief add_filter - add/modify filter * @brief add_filter - add/modify filter
* @param str - string in format "bank# FIFO# mode num0 .. num3" * @param str - string in format "bank# FIFO# mode num0 .. num3"
@ -414,10 +428,12 @@ const char *helpmsg =
"https://github.com/eddyem/stm32samples/tree/master/F0-nolib/usbcan_ringbuffer build#" BUILD_NUMBER " @ " BUILD_DATE "\n" "https://github.com/eddyem/stm32samples/tree/master/F0-nolib/usbcan_ringbuffer build#" BUILD_NUMBER " @ " BUILD_DATE "\n"
"'a' - add ID to ignore list (max 10 IDs)\n" "'a' - add ID to ignore list (max 10 IDs)\n"
"'b' - reinit CAN with given baudrate\n" "'b' - reinit CAN with given baudrate\n"
"'c' - get CAN status\n"
"'d' - delete ignore list\n" "'d' - delete ignore list\n"
"'D' - activate DFU mode\n" "'D' - activate DFU mode\n"
"'e' - get CAN errcodes\n"
"'f' - add/delete filter, format: bank# FIFO# mode(M/I) num0 [num1 [num2 [num3]]]\n" "'f' - add/delete filter, format: bank# FIFO# mode(M/I) num0 [num1 [num2 [num3]]]\n"
"'F' - USB_sendstr/clear flood message: F ID byte0 ... byteN\n" "'F' - send/clear flood message: F ID byte0 ... byteN\n"
"'I' - reinit CAN\n" "'I' - reinit CAN\n"
"'l' - list all active filters\n" "'l' - list all active filters\n"
"'o' - turn LEDs OFF\n" "'o' - turn LEDs OFF\n"
@ -425,10 +441,22 @@ const char *helpmsg =
"'p' - print ignore buffer\n" "'p' - print ignore buffer\n"
"'P' - pause/resume in packets displaying\n" "'P' - pause/resume in packets displaying\n"
"'R' - software reset\n" "'R' - software reset\n"
"'s/S' - USB_sendstr data over CAN: s ID byte0 .. byteN\n" "'s/S' - send data over CAN: s ID byte0 .. byteN\n"
"'t' - change flood period (>=1ms)\n"
"'T' - get time from start (ms)\n" "'T' - get time from start (ms)\n"
; ;
TRUE_INLINE void getcanstat(){
USB_sendstr("CAN_MSR=");
printuhex(CAN->MSR);
USB_sendstr("\nCAN_TSR=");
printuhex(CAN->TSR);
USB_sendstr("\nCAN_RF0R=");
printuhex(CAN->RF0R);
USB_sendstr("\nCAN_RF1R=");
printuhex(CAN->RF1R);
}
/** /**
* @brief cmd_parser - command parsing * @brief cmd_parser - command parsing
* @param txt - buffer with commands & data * @param txt - buffer with commands & data
@ -436,37 +464,48 @@ const char *helpmsg =
*/ */
void cmd_parser(char *txt){ void cmd_parser(char *txt){
char _1st = txt[0]; char _1st = txt[0];
++txt;
/* /*
* parse long commands here * parse long commands here
*/ */
switch(_1st){ switch(_1st){
case 'a': case 'a':
addIGN(txt + 1); addIGN(txt);
goto eof; goto eof;
break; break;
case 'b': case 'b':
CANini(txt + 1); CANini(txt);
goto eof; goto eof;
break; break;
case 'f': case 'f':
add_filter(txt + 1); add_filter(txt);
goto eof; goto eof;
break; break;
case 'F': case 'F':
set_flood(parseCANmsg(txt + 1)); set_flood(parseCANmsg(txt));
goto eof; goto eof;
break; break;
case 's': case 's':
case 'S': case 'S':
USB_sendstrCANcommand(txt + 1); USB_sendstrCANcommand(txt);
goto eof;
break;
case 't':
setfloodt(txt);
goto eof; goto eof;
break; break;
} }
if(txt[1] != '\n') *txt = '?'; // help for wrong message length if(*txt != '\n') _1st = '?'; // help for wrong message length
switch(_1st){ switch(_1st){
case 'c':
getcanstat();
break;
case 'd': case 'd':
IgnSz = 0; IgnSz = 0;
break; break;
case 'e':
printCANerr();
break;
case 'D': case 'D':
USB_sendstr("Go into DFU mode\n"); USB_sendstr("Go into DFU mode\n");
USB_sendall(); USB_sendall();

View File

@ -0,0 +1 @@
-std=c17

View File

@ -0,0 +1,5 @@
// Add predefined macros for your project here. For example:
// #define THE_ANSWER 42
#define EBUG
#define STM32F0
#define STM32F042x6

View File

@ -0,0 +1 @@
[General]

View File

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 6.0.0, 2022-10-28T17:08:49. -->
<qtcreator>
<data>
<variable>EnvironmentId</variable>
<value type="QByteArray">{cf63021e-ef53-49b0-b03b-2f2570cdf3b6}</value>
</data>
<data>
<variable>ProjectExplorer.Project.ActiveTarget</variable>
<value type="int">0</value>
</data>
<data>
<variable>ProjectExplorer.Project.EditorSettings</variable>
<valuemap type="QVariantMap">
<value type="bool" key="EditorConfiguration.AutoIndent">true</value>
<value type="bool" key="EditorConfiguration.AutoSpacesForTabs">false</value>
<value type="bool" key="EditorConfiguration.CamelCaseNavigation">true</value>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.0">
<value type="QString" key="language">Cpp</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">CppGlobal</value>
</valuemap>
</valuemap>
<valuemap type="QVariantMap" key="EditorConfiguration.CodeStyle.1">
<value type="QString" key="language">QmlJS</value>
<valuemap type="QVariantMap" key="value">
<value type="QByteArray" key="CurrentPreferences">QmlJSGlobal</value>
</valuemap>
</valuemap>
<value type="int" key="EditorConfiguration.CodeStyle.Count">2</value>
<value type="QByteArray" key="EditorConfiguration.Codec">KOI8-R</value>
<value type="bool" key="EditorConfiguration.ConstrainTooltips">false</value>
<value type="int" key="EditorConfiguration.IndentSize">4</value>
<value type="bool" key="EditorConfiguration.KeyboardTooltips">false</value>
<value type="int" key="EditorConfiguration.MarginColumn">80</value>
<value type="bool" key="EditorConfiguration.MouseHiding">true</value>
<value type="bool" key="EditorConfiguration.MouseNavigation">true</value>
<value type="int" key="EditorConfiguration.PaddingMode">1</value>
<value type="bool" key="EditorConfiguration.PreferSingleLineComments">false</value>
<value type="bool" key="EditorConfiguration.ScrollWheelZooming">false</value>
<value type="bool" key="EditorConfiguration.ShowMargin">false</value>
<value type="int" key="EditorConfiguration.SmartBackspaceBehavior">1</value>
<value type="bool" key="EditorConfiguration.SmartSelectionChanging">true</value>
<value type="bool" key="EditorConfiguration.SpacesForTabs">true</value>
<value type="int" key="EditorConfiguration.TabKeyBehavior">0</value>
<value type="int" key="EditorConfiguration.TabSize">8</value>
<value type="bool" key="EditorConfiguration.UseGlobal">true</value>
<value type="bool" key="EditorConfiguration.UseIndenter">false</value>
<value type="int" key="EditorConfiguration.Utf8BomBehavior">2</value>
<value type="bool" key="EditorConfiguration.addFinalNewLine">true</value>
<value type="bool" key="EditorConfiguration.cleanIndentation">true</value>
<value type="bool" key="EditorConfiguration.cleanWhitespace">true</value>
<value type="QString" key="EditorConfiguration.ignoreFileTypes">*.md, *.MD, Makefile</value>
<value type="bool" key="EditorConfiguration.inEntireDocument">true</value>
<value type="bool" key="EditorConfiguration.skipTrailingWhitespace">true</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.PluginSettings</variable>
<valuemap type="QVariantMap">
<valuemap type="QVariantMap" key="ClangTools">
<value type="bool" key="ClangTools.AnalyzeOpenFiles">true</value>
<value type="bool" key="ClangTools.BuildBeforeAnalysis">true</value>
<value type="QString" key="ClangTools.DiagnosticConfig">Builtin.DefaultTidyAndClazy</value>
<value type="int" key="ClangTools.ParallelJobs">4</value>
<valuelist type="QVariantList" key="ClangTools.SelectedDirs"/>
<valuelist type="QVariantList" key="ClangTools.SelectedFiles"/>
<valuelist type="QVariantList" key="ClangTools.SuppressedDiagnostics"/>
<value type="bool" key="ClangTools.UseGlobalSettings">true</value>
</valuemap>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.Target.0</variable>
<valuemap type="QVariantMap">
<value type="QString" key="DeviceType">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Desktop</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{91347f2c-5221-46a7-80b1-0a054ca02f79}</value>
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/eddy/Docs/SAO/ELECTRONICS/STM32/F0-srcs/usbcan_ringbuffer</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
<value type="QString">all</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Сборка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
</valuemap>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<valuelist type="QVariantList" key="GenericProjectManager.GenericMakeStep.BuildTargets">
<value type="QString">clean</value>
</valuelist>
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericMakeStep</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Очистка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Очистка</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.CustomParsers"/>
<value type="bool" key="ProjectExplorer.BuildConfiguration.ParseStandardOutput">false</value>
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">По умолчанию</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">GenericProjectManager.GenericBuildConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.DeployConfiguration.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">0</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Развёртывание</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Развёртывание</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Deploy</value>
</valuemap>
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.DeployConfiguration.CustomData"/>
<value type="bool" key="ProjectExplorer.DeployConfiguration.CustomDataEnabled">false</value>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.DefaultDeployConfiguration</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">1</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
<valuelist type="QVariantList" key="CustomOutputParsers"/>
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
<value type="QString" key="ProjectExplorer.RunConfiguration.BuildKey"></value>
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
</valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap>
</data>
<data>
<variable>ProjectExplorer.Project.TargetCount</variable>
<value type="int">1</value>
</data>
<data>
<variable>ProjectExplorer.Project.Updater.FileVersion</variable>
<value type="int">22</value>
</data>
<data>
<variable>Version</variable>
<value type="int">22</value>
</data>
</qtcreator>

View File

@ -0,0 +1 @@
-std=c++17

View File

@ -0,0 +1,16 @@
can.c
can.h
hardware.c
hardware.h
main.c
proto.c
proto.h
ringbuffer.c
ringbuffer.h
usb.c
usb.h
usb_defs.h
usb_lib.c
usb_lib.h
usbhw.c
usbhw.h

View File

@ -0,0 +1,6 @@
.
../inc
../inc/Fx
../inc/cm
../inc/ld
../inc/startup

View File

@ -1,2 +1,2 @@
#define BUILD_NUMBER "1" #define BUILD_NUMBER "23"
#define BUILD_DATE "2022-10-28" #define BUILD_DATE "2022-12-05"

Binary file not shown.

View File

@ -157,6 +157,6 @@ dfuboot: $(BIN)
openocd: openocd:
openocd -f openocd.cfg openocd -f openocd.cfg
dbg: dbg:
arm-none-eabi-gdb $(ELF) -ex 'target remote localhost:3333' -ex 'monitor reset halt' arm-none-eabi-gdb $(ELF) -ex 'target extended-remote localhost:3333' -ex 'monitor reset halt'
.PHONY: size clean flash boot dfuboot openocd dbg .PHONY: size clean flash boot dfuboot openocd dbg

View File

@ -1,2 +1,4 @@
CAN bus (PB8/PB9) <> UART1 (PA9/PA10) CAN bus (PB8/PB9) <> UART1 (PA9/PA10)
The same thing as canusb for STM32F0x2 The same thing as canusb for STM32F0x2
Baudrate - 921600

View File

@ -30,6 +30,7 @@ static CAN_message messages[CAN_INMESSAGE_SIZE];
static uint8_t first_free_idx = 0; // index of first empty cell 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 int8_t first_nonfree_idx = -1; // index of first data cell
static uint16_t oldspeed = 100; // speed of last init static uint16_t oldspeed = 100; // speed of last init
uint32_t floodT = FLOOD_PERIOD_MS-1; // flood period in ms
static uint32_t last_err_code = 0; static uint32_t last_err_code = 0;
static CAN_status can_status = CAN_STOP; static CAN_status can_status = CAN_STOP;
@ -229,7 +230,7 @@ void can_proc(){
CAN_setup(0); CAN_setup(0);
} }
static uint32_t lastFloodTime = 0; static uint32_t lastFloodTime = 0;
if(flood_msg && (Tms - lastFloodTime) > (FLOOD_PERIOD_MS-1)){ // flood every ~5ms if(flood_msg && (Tms - lastFloodTime) > (floodT)){ // flood every ~5ms
lastFloodTime = Tms; lastFloodTime = Tms;
can_send(flood_msg->data, flood_msg->length, flood_msg->ID); can_send(flood_msg->data, flood_msg->length, flood_msg->ID);
} }

View File

@ -27,6 +27,7 @@
// incoming message buffer size // incoming message buffer size
#define CAN_INMESSAGE_SIZE (8) #define CAN_INMESSAGE_SIZE (8)
extern uint32_t floodT;
// CAN message // CAN message
typedef struct{ typedef struct{

View File

@ -30,9 +30,7 @@ void sys_tick_handler(void){
int main(void){ int main(void){
uint32_t lastT = 0; uint32_t lastT = 0;
#ifdef BLUEPILL
uint32_t bplastT = 0; uint32_t bplastT = 0;
#endif
CAN_message *can_mesg; CAN_message *can_mesg;
StartHSE(); StartHSE();
SysTick_Config(72000); SysTick_Config(72000);
@ -50,12 +48,13 @@ int main(void){
LED_off(LED0); LED_off(LED0);
lastT = 0; lastT = 0;
} }
#ifdef BLUEPILL
if(Tms - bplastT > 499){ if(Tms - bplastT > 499){
usart_transmit();
#ifdef BLUEPILL
pin_toggle(LEDB_port, LEDB_pin); pin_toggle(LEDB_port, LEDB_pin);
#endif
bplastT = Tms; bplastT = Tms;
} }
#endif
can_proc(); can_proc();
CAN_status st = CAN_get_status(); CAN_status st = CAN_get_status();
if(st == CAN_FIFO_OVERRUN){ if(st == CAN_FIFO_OVERRUN){
@ -63,30 +62,34 @@ int main(void){
}else if(st == CAN_ERR){ }else if(st == CAN_ERR){
usart_send("Some CAN error occured\n"); usart_send("Some CAN error occured\n");
} }
int errflag = 0;
while((can_mesg = CAN_messagebuf_pop())){ while((can_mesg = CAN_messagebuf_pop())){
IWDG->KR = IWDG_REFRESH;
if(can_mesg && isgood(can_mesg->ID)){ if(can_mesg && isgood(can_mesg->ID)){
LED_on(LED0); LED_on(LED0);
lastT = Tms; lastT = Tms;
if(!lastT) lastT = 1; if(!lastT) lastT = 1;
if(ShowMsgs){ // new data in buff if(ShowMsgs){ // new data in buff
IWDG->KR = IWDG_REFRESH;
uint8_t len = can_mesg->length; uint8_t len = can_mesg->length;
printu(Tms); printu(Tms);
usart_send(" #"); if(!usart_send(" #")) errflag = 1;
printuhex(can_mesg->ID); printuhex(can_mesg->ID);
for(uint8_t ctr = 0; ctr < len; ++ctr){ for(uint8_t ctr = 0; ctr < len; ++ctr){
usart_putchar(' '); if(!usart_putchar(' ')) errflag = 1;
printuhex(can_mesg->data[ctr]); printuhex(can_mesg->data[ctr]);
} }
usart_putchar('\n'); if(!usart_putchar('\n')) errflag = 1;
} }
} }
} }
char *str; char *str;
int g = usart_getline(&str); int g = usart_getline(&str);
if(g < 0) usart_send("USART buffer overflow!\n"); if(g < 0) usart_send("USART IN buffer overflow!\n");
else if(g > 0) cmd_parser(str); else if(g > 0) cmd_parser(str);
usart_transmit(); if(errflag){
while(!usart_txrdy) IWDG->KR = IWDG_REFRESH;
usart_send("USART OUT buffer overflow!\n");
}
} }
return 0; return 0;
} }

View File

@ -137,6 +137,7 @@ static char *getbin(const char *buf, uint32_t *N){
char *getnum(const char *txt, uint32_t *N){ char *getnum(const char *txt, uint32_t *N){
char *nxt = NULL; char *nxt = NULL;
char *s = omit_spaces(txt); char *s = omit_spaces(txt);
if(!*s) return (char*)txt;
if(*s == '0'){ // hex, oct or 0 if(*s == '0'){ // hex, oct or 0
if(s[1] == 'x' || s[1] == 'X'){ // hex if(s[1] == 'x' || s[1] == 'X'){ // hex
nxt = gethex(s+2, N); nxt = gethex(s+2, N);
@ -166,7 +167,6 @@ static CAN_message *parseCANmsg(char *txt){
int ctr = -1; int ctr = -1;
canmsg.ID = 0xffff; canmsg.ID = 0xffff;
do{ do{
txt = omit_spaces(txt);
n = getnum(txt, &N); n = getnum(txt, &N);
if(txt == n) break; if(txt == n) break;
txt = n; txt = n;
@ -206,14 +206,13 @@ TRUE_INLINE void usart_sendCANcommand(char *txt){
} }
CAN_message *msg = parseCANmsg(txt); CAN_message *msg = parseCANmsg(txt);
if(!msg) return; if(!msg) return;
uint32_t N = 3; uint32_t N = 5;
while(CAN_BUSY == can_send(msg->data, msg->length, msg->ID)){ while(CAN_BUSY == can_send(msg->data, msg->length, msg->ID)){
if(--N == 0) break; if(--N == 0) break;
} }
} }
TRUE_INLINE void CANini(char *txt){ TRUE_INLINE void CANini(char *txt){
txt = omit_spaces(txt);
uint32_t N; uint32_t N;
char *n = getnum(txt, &N); char *n = getnum(txt, &N);
if(txt == n){ if(txt == n){
@ -237,7 +236,6 @@ TRUE_INLINE void addIGN(char *txt){
usart_send("Ignore buffer is full"); usart_send("Ignore buffer is full");
return; return;
} }
txt = omit_spaces(txt);
uint32_t N; uint32_t N;
char *n = getnum(txt, &N); char *n = getnum(txt, &N);
if(txt == n){ if(txt == n){
@ -333,7 +331,6 @@ TRUE_INLINE void list_filters(){
*/ */
static void add_filter(char *str){ static void add_filter(char *str){
uint32_t N; uint32_t N;
str = omit_spaces(str);
char *n = getnum(str, &N); char *n = getnum(str, &N);
if(n == str){ if(n == str){
usart_send("No bank# given"); usart_send("No bank# given");
@ -431,6 +428,7 @@ const char *helpmsg =
"'P' - pause/resume in packets displaying\n" "'P' - pause/resume in packets displaying\n"
"'R' - software reset\n" "'R' - software reset\n"
"'s/S' - usart_send data over CAN: s ID byte0 .. byteN\n" "'s/S' - usart_send data over CAN: s ID byte0 .. byteN\n"
"'t' - change flood period (>=1ms)\n"
"'T' - get time from start (ms)\n" "'T' - get time from start (ms)\n"
; ;
@ -445,39 +443,54 @@ TRUE_INLINE void getcanstat(){
printuhex(CAN1->RF1R); printuhex(CAN1->RF1R);
} }
TRUE_INLINE void setfloodt(char *s){
uint32_t N;
char *n = getnum(s, &N);
if(s == n || N == 0){
usart_send("t="); printu(floodT); usart_putchar('\n');
return;
}
floodT = N - 1;
}
/** /**
* @brief cmd_parser - command parsing * @brief cmd_parser - command parsing
* @param txt - buffer with commands & data * @param txt - buffer with commands & data
*/ */
void cmd_parser(char *txt){ void cmd_parser(char *txt){
char _1st = txt[0]; char _1st = txt[0];
++txt;
/* /*
* parse long commands here * parse long commands here
*/ */
switch(_1st){ switch(_1st){
case 'a': case 'a':
addIGN(txt + 1); addIGN(txt);
goto eof; goto eof;
break; break;
case 'b': case 'b':
CANini(txt + 1); CANini(txt);
goto eof; goto eof;
break; break;
case 'f': case 'f':
add_filter(txt + 1); add_filter(txt);
goto eof; goto eof;
break; break;
case 'F': case 'F':
set_flood(parseCANmsg(txt + 1)); set_flood(parseCANmsg(txt));
goto eof; goto eof;
break; break;
case 's': case 's':
case 'S': case 'S':
usart_sendCANcommand(txt + 1); usart_sendCANcommand(txt);
goto eof;
break;
case 't':
setfloodt(txt);
goto eof; goto eof;
break; break;
} }
if(txt[1] != '\n') *txt = '?'; // help for wrong message length if(txt[1] != 0) _1st = '?'; // help for wrong message length
switch(_1st){ switch(_1st){
case 'c': case 'c':
getcanstat(); getcanstat();

View File

@ -53,11 +53,18 @@ int usart_getline(char **line){
} }
// transmit current tbuf and swap buffers // transmit current tbuf and swap buffers
void usart_transmit(){ int usart_transmit(){
register int l = odatalen[tbufno]; register int l = odatalen[tbufno];
if(!l) return; if(!l) return 0;
uint32_t tmout = 16000000; uint32_t tmout = 1600000;
while(!usart_txrdy){if(--tmout == 0) return;}; // wait for previos buffer transmission /*tbuf[tbufno][0] = '*';
tbuf[tbufno][1] = '0' + tbufno;
tbuf[tbufno][l-1] = '*';
tbuf[tbufno][l-2] = '0' + tbufno;*/
while(!usart_txrdy){
IWDG->KR = IWDG_REFRESH;
if(--tmout == 0) return 0;
}; // wait for previos buffer transmission
usart_txrdy = 0; usart_txrdy = 0;
odatalen[tbufno] = 0; odatalen[tbufno] = 0;
DMA1_Channel4->CCR &= ~DMA_CCR_EN; DMA1_Channel4->CCR &= ~DMA_CCR_EN;
@ -65,18 +72,27 @@ void usart_transmit(){
DMA1_Channel4->CNDTR = l; DMA1_Channel4->CNDTR = l;
DMA1_Channel4->CCR |= DMA_CCR_EN; DMA1_Channel4->CCR |= DMA_CCR_EN;
tbufno = !tbufno; tbufno = !tbufno;
return l;
} }
void usart_putchar(const char ch){ int usart_putchar(const char ch){
if(odatalen[tbufno] == UARTBUFSZO) usart_transmit(); if(odatalen[tbufno] == UARTBUFSZO){
if(!usart_transmit()) return 0;
}
tbuf[tbufno][odatalen[tbufno]++] = ch; tbuf[tbufno][odatalen[tbufno]++] = ch;
return 1;
} }
void usart_send(const char *str){ int usart_send(const char *str){
int l = 0;
while(*str){ while(*str){
if(odatalen[tbufno] == UARTBUFSZO) usart_transmit(); if(odatalen[tbufno] == UARTBUFSZO){
tbuf[tbufno][odatalen[tbufno]++] = *str++; if(!usart_transmit()) return 0;
} }
tbuf[tbufno][odatalen[tbufno]++] = *str++;
++l;
}
return l;
} }
/* /*
@ -102,7 +118,7 @@ void usart_setup(){
NVIC_EnableIRQ(DMA1_Channel4_IRQn); NVIC_EnableIRQ(DMA1_Channel4_IRQn);
NVIC_SetPriority(USART1_IRQn, 0); NVIC_SetPriority(USART1_IRQn, 0);
// setup usart1 // setup usart1
USART1->BRR = 72000000 / 115200; USART1->BRR = 72000000 / 921600;
USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART USART1->CR1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_UE; // 1start,8data,nstop; enable Rx,Tx,USART
while(!(USART1->SR & USART_SR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission while(!(USART1->SR & USART_SR_TC)){if(--tmout == 0) break;} // polling idle frame Transmission
USART1->SR = 0; // clear flags USART1->SR = 0; // clear flags
@ -116,15 +132,15 @@ void usart1_isr(){
if(USART1->SR & USART_SR_RXNE){ // RX not emty - receive next char if(USART1->SR & USART_SR_RXNE){ // RX not emty - receive next char
uint8_t rb = USART1->DR; uint8_t rb = USART1->DR;
if(idatalen[rbufno] < UARTBUFSZI){ // put next char into buf if(idatalen[rbufno] < UARTBUFSZI){ // put next char into buf
rbuf[rbufno][idatalen[rbufno]++] = rb;
if(rb == '\n'){ // got newline - line ready if(rb == '\n'){ // got newline - line ready
rbuf[rbufno][idatalen[rbufno]] = 0;
usart_linerdy = 1; usart_linerdy = 1;
dlen = idatalen[rbufno]; dlen = idatalen[rbufno];
recvdata = rbuf[rbufno]; recvdata = rbuf[rbufno];
// prepare other buffer // prepare other buffer
rbufno = !rbufno; rbufno = !rbufno;
idatalen[rbufno] = 0; idatalen[rbufno] = 0;
} }else rbuf[rbufno][idatalen[rbufno]++] = rb;
}else{ // buffer overrun }else{ // buffer overrun
usart_bufovr = 1; usart_bufovr = 1;
idatalen[rbufno] = 0; idatalen[rbufno] = 0;

View File

@ -19,16 +19,16 @@
#pragma once #pragma once
// input and output buffers size // input and output buffers size
#define UARTBUFSZI (128) #define UARTBUFSZI (256)
#define UARTBUFSZO (128) #define UARTBUFSZO (1024)
#define usartrx() (usart_linerdy) #define usartrx() (usart_linerdy)
#define usartovr() (usart_bufovr) #define usartovr() (usart_bufovr)
extern volatile int usart_txrdy; extern volatile int usart_txrdy;
void usart_transmit(); int usart_transmit();
void usart_setup(); void usart_setup();
int usart_getline(char **line); int usart_getline(char **line);
void usart_send(const char *str); int usart_send(const char *str);
void usart_putchar(const char ch); int usart_putchar(const char ch);

View File

@ -1,2 +1,2 @@
#define BUILD_NUMBER "64" #define BUILD_NUMBER "98"
#define BUILD_DATE "2022-12-05" #define BUILD_DATE "2022-12-05"