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

This commit is contained in:
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
# change this linking script depending on particular MCU model,
LDSCRIPT ?= stm32f042x6.ld
#DEFS = -DEBUG
# autoincremental version & build date
VERSION_FILE = version.inc

View File

@@ -21,17 +21,14 @@
#include "proto.h"
#include "usb.h"
#include <string.h> // 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
uint32_t floodT = FLOOD_PERIOD_MS-1; // flood period in ms
#ifdef EBUG
static uint32_t last_err_code = 0;
#endif
static CAN_status can_status = CAN_STOP;
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
}
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?
if(first_free_idx == CAN_INMESSAGE_SIZE) first_free_idx = 0;
return 0;
@@ -146,9 +143,7 @@ void CAN_setup(uint16_t speed){
/* (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 */
@@ -174,6 +169,36 @@ void CAN_setup(uint16_t speed){
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(){
#ifdef EBUG
if(last_err_code){
@@ -193,27 +218,7 @@ void can_proc(){
IWDG->KR = IWDG_REFRESH;
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("Receive error counter: ");
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');
printCANerr();
// request abort for all mailboxes
CAN->TSR |= CAN_TSR_ABRQ0 | CAN_TSR_ABRQ1 | CAN_TSR_ABRQ2;
// reset CAN bus
@@ -222,7 +227,7 @@ void can_proc(){
CAN_setup(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;
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){
if(!msg) flood_msg = NULL;
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;
}
}
@@ -364,3 +383,4 @@ void cec_can_isr(){
#endif
}
}

View File

@@ -18,7 +18,7 @@
#pragma once
#include "hardware.h"
#include <stdint.h>
// amount of filter banks in STM32F0
#define STM32F0FBANKNO 28
@@ -28,6 +28,8 @@
// incoming message buffer size
#define CAN_INMESSAGE_SIZE (8)
extern uint32_t floodT;
// CAN message
typedef struct{
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);
void can_proc();
void printCANerr();
CAN_message *CAN_messagebuf_pop();

View File

@@ -68,7 +68,7 @@ int main(void){
USB_sendstr(" #");
printuhex(can_mesg->ID);
for(uint8_t ctr = 0; ctr < len; ++ctr){
USB_putbyte('\n');
USB_putbyte(' ');
printuhex(can_mesg->data[ctr]);
}
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 *nxt = NULL;
char *s = omit_spaces(txt);
if(!*s) return (char*)txt;
if(*s == '0'){ // hex, oct or 0
if(s[1] == 'x' || s[1] == 'X'){ // hex
nxt = gethex(s+2, N);
@@ -166,7 +167,6 @@ static CAN_message *parseCANmsg(char *txt){
int ctr = -1;
canmsg.ID = 0xffff;
do{
txt = omit_spaces(txt);
n = getnum(txt, &N);
if(txt == n) break;
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)
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);
if(!msg) return;
uint32_t N = 1000000;
uint32_t N = 5;
while(CAN_BUSY == can_send(msg->data, msg->length, msg->ID)){
if(--N == 0) break;
}
}
TRUE_INLINE void CANini(char *txt){
txt = omit_spaces(txt);
uint32_t N;
char *n = getnum(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
* @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"
"'a' - add ID to ignore list (max 10 IDs)\n"
"'b' - reinit CAN with given baudrate\n"
"'c' - get CAN status\n"
"'d' - delete ignore list\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' - USB_sendstr/clear flood message: F ID byte0 ... byteN\n"
"'F' - send/clear flood message: F ID byte0 ... byteN\n"
"'I' - reinit CAN\n"
"'l' - list all active filters\n"
"'o' - turn LEDs OFF\n"
@@ -425,10 +441,22 @@ const char *helpmsg =
"'p' - print ignore buffer\n"
"'P' - pause/resume in packets displaying\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"
;
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
* @param txt - buffer with commands & data
@@ -436,37 +464,48 @@ const char *helpmsg =
*/
void cmd_parser(char *txt){
char _1st = txt[0];
++txt;
/*
* parse long commands here
*/
switch(_1st){
case 'a':
addIGN(txt + 1);
addIGN(txt);
goto eof;
break;
case 'b':
CANini(txt + 1);
CANini(txt);
goto eof;
break;
case 'f':
add_filter(txt + 1);
add_filter(txt);
goto eof;
break;
case 'F':
set_flood(parseCANmsg(txt + 1));
set_flood(parseCANmsg(txt));
goto eof;
break;
case 's':
case 'S':
USB_sendstrCANcommand(txt + 1);
USB_sendstrCANcommand(txt);
goto eof;
break;
case 't':
setfloodt(txt);
goto eof;
break;
}
if(txt[1] != '\n') *txt = '?'; // help for wrong message length
if(*txt != '\n') _1st = '?'; // help for wrong message length
switch(_1st){
case 'c':
getcanstat();
break;
case 'd':
IgnSz = 0;
break;
case 'e':
printCANerr();
break;
case 'D':
USB_sendstr("Go into DFU mode\n");
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_DATE "2022-10-28"
#define BUILD_NUMBER "23"
#define BUILD_DATE "2022-12-05"