Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions include/canmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ class CanMap: CanCallback
uint8_t next;
};

CanMap(CanHardware* hw, bool loadFromFlash = true);
explicit CanMap(CanHardware* hw, bool loadFromFlash = true);
CanHardware* GetHardware() { return canHardware; }
void HandleClear() override;
void HandleRx(uint32_t canId, uint32_t data[2], uint8_t dlc) override;
Expand Down Expand Up @@ -95,7 +95,6 @@ class CanMap: CanCallback
CANIDMAP canSendMap[MAX_MESSAGES];
CANIDMAP canRecvMap[MAX_MESSAGES];
CANPOS canPosMap[MAX_ITEMS + 1]; //Last item is a "tail"
uint32_t lastRxTimestamp;

void ClearMap(CANIDMAP *canMap);
int Add(CANIDMAP *canMap, Param::PARAM_NUM param, uint32_t canId, uint8_t offsetBits, int8_t length, float gain, int8_t offset);
Expand Down
8 changes: 5 additions & 3 deletions include/cansdo.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ class CanSdo: CanCallback, public IPutChar
} __attribute__((packed));

/** Default constructor */
CanSdo(CanHardware* hw, CanMap* cm = 0);
explicit CanSdo(CanHardware* hw, CanMap* cm = 0);
CanHardware* GetHardware() { return canHardware; }
void HandleClear();
void HandleClear() override;
void HandleRx(uint32_t canId, uint32_t data[2], uint8_t dlc) override;
void SDOWrite(uint8_t nodeId, uint16_t index, uint8_t subIndex, uint32_t data);
void SDORead(uint8_t nodeId, uint16_t index, uint8_t subIndex);
Expand All @@ -64,7 +64,8 @@ class CanSdo: CanCallback, public IPutChar
int GetPrintRequest() { return printRequest; }
SdoFrame* GetPendingUserspaceSdo() { return pendingUserSpaceSdo ? &pendingUserSpaceSdoFrame : 0; }
void SendSdoReply(SdoFrame* sdoFrame);
void PutChar(char c);
void PutChar(char c) override;
void TriggerTimeout(int callingFrequency);

private:
CanHardware* canHardware;
Expand All @@ -78,6 +79,7 @@ class CanSdo: CanCallback, public IPutChar
volatile char printBuffer[64]; //Must be a power of 2 for efficient modulo calculation
volatile uint32_t printByteIn;
volatile uint32_t printByteOut;
volatile int printTimeout; //remaining time to wait
Param::PARAM_NUM mapParam;
uint32_t mapId;
CanMap::CANPOS mapInfo;
Expand Down
34 changes: 34 additions & 0 deletions include/cortex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* This file is part of the libopeninv project.
*
* Copyright (C) 2025 David J. Fiddes <D.J@fiddes.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef CORTEX_H
#define CORTEX_H

#include <stdint.h>

/** Do not mask any interrupts */
#define CM_BASEPRI_ENABLE_INTERRUPTS 0

/** \brief Set the BASEPRI register to the given priority level */
inline __attribute__((always_inline)) void cm_set_basepriority(uint32_t new_priority)
{
__asm__ volatile("msr basepri, %0 " ::"r"(new_priority) : "memory");
}

#endif // CORTEX_H
1 change: 0 additions & 1 deletion include/stm32_can.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ class Stm32Can: public CanHardware
void SetFilterBank(int& idIndex, int& filterId, uint16_t* idList);
void SetFilterBankMask(int& idIndex, int& filterId, uint16_t* idMaskList);
void SetFilterBank29(int& idIndex, int& filterId, uint32_t* idList);
uint32_t GetFlashAddress();

static Stm32Can* interfaces[];
};
Expand Down
30 changes: 28 additions & 2 deletions src/cansdo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#define PRINT_BUF_ENQUEUE(c) printBuffer[(printByteIn++) & (sizeof(printBuffer) - 1)] = c
#define PRINT_BUF_DEQUEUE() printBuffer[(printByteOut++) & (sizeof(printBuffer) - 1)]
#define PRINT_BUF_EMPTY() ((printByteOut - printByteIn) == sizeof(printBuffer))
#define PRINT_TIMEOUT 1000

/** \brief
*
Expand All @@ -44,7 +45,10 @@
*
*/
CanSdo::CanSdo(CanHardware* hw, CanMap* cm)
: canHardware(hw), canMap(cm), nodeId(1), remoteNodeId(255), printRequest(-1)
: canHardware(hw), canMap(cm), nodeId(1), remoteNodeId(255), printRequest(-1),
printByteIn(0), printByteOut(sizeof(printBuffer)), printTimeout(PRINT_TIMEOUT),
mapParam(Param::PARAM_INVALID), mapId(0), sdoReplyValid(false), sdoReplyData(0),
pendingUserSpaceSdo(false)
{
canHardware->AddCallback(this);
HandleClear();
Expand Down Expand Up @@ -234,10 +238,31 @@ void CanSdo::ProcessSDO(uint32_t data[2])
canHardware->Send(0x580 + nodeId, data);
}

/** \brief count down PutChar character send timeout
*
* \param callingFrequency in ms. This is subtracted from the remaining wait time
* \return void
*
*/
void CanSdo::TriggerTimeout(int callingFrequency)
{
if (printTimeout > 0)
{
printTimeout -= callingFrequency;
}
if (printTimeout < 0)
{
printTimeout = 0;
}
}

void CanSdo::PutChar(char c)
{
if (printTimeout == 0) return; //last call to PutChar resulted in a timeout. Do not recover until the next burst

printTimeout = PRINT_TIMEOUT;
//When print buffer is full, wait
while (printByteIn == printByteOut);
while (printByteIn == printByteOut && printTimeout > 0);

PRINT_BUF_ENQUEUE(c);
printRequest = -1; //We can clear the print start trigger as we've obviously started printing
Expand All @@ -257,6 +282,7 @@ bool CanSdo::ProcessSpecialSDOObjects(SdoFrame* sdo)
{
sdo->data = 65535; //this should be the size of JSON but we don't know this in advance. Hmm.
sdo->cmd = SDO_RESPONSE_UPLOAD | SDO_SIZE_SPECIFIED;
printTimeout = PRINT_TIMEOUT;
printByteIn = 0;
printByteOut = sizeof(printBuffer); //both point to the beginning of the physical buffer but virtually they are 64 bytes apart
printRequest = sdo->subIndex;
Expand Down
28 changes: 27 additions & 1 deletion src/stm32_can.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@
#include <libopencm3/cm3/common.h>
#include <libopencm3/cm3/nvic.h>
#include "stm32_can.h"
#include "cortex.h"

//Some functions use the "register" keyword which C++ doesn't like
//We can safely ignore that as we don't even use those functions
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wregister"
#include <libopencm3/cm3/cortex.h>
#pragma GCC diagnostic pop

#define MAX_INTERFACES 2
#define IDS_PER_BANK 4
Expand All @@ -37,6 +45,21 @@
#define CAN_PERIPH_SPEED 36
#endif // CAN_PERIPH_SPEED

// To allow concurrent sending of CAN frames from different contexts we need to
// disable interrupts. Some projects have hard realtime requirements which mean
// we cannot disable all interrupts. These projects should define the highest
// interrupt priority users of the CAN interface here. If not defined we assume
// that all interrupts can be disabled.
//
// CAN_MAX_IRQ_PRIORITY should match the priority passed to nvic_set_priority()
#ifdef CAN_MAX_IRQ_PRIORITY
#define DISABLE_CAN_USER_INTERRUPTS() cm_set_basepriority(CAN_MAX_IRQ_PRIORITY);
#define ENABLE_CAN_USER_INTERRUPTS() cm_set_basepriority(CM_BASEPRI_ENABLE_INTERRUPTS);
#else
#define DISABLE_CAN_USER_INTERRUPTS() cm_disable_interrupts()
#define ENABLE_CAN_USER_INTERRUPTS() cm_enable_interrupts()
#endif // CAN_MAX_IRQ_PRIORITY

struct CANSPEED
{
uint32_t ts1;
Expand Down Expand Up @@ -198,6 +221,8 @@ void Stm32Can::SetBaudrate(enum baudrates baudrate)
*/
void Stm32Can::Send(uint32_t canId, uint32_t data[2], uint8_t len)
{
DISABLE_CAN_USER_INTERRUPTS();

can_disable_irq(canDev, CAN_IER_TMEIE);

if (can_transmit(canDev, canId, canId > 0x7FF, false, len, (uint8_t*)data) < 0 && sendCnt < SENDBUFFER_LEN)
Expand All @@ -214,8 +239,9 @@ void Stm32Can::Send(uint32_t canId, uint32_t data[2], uint8_t len)
{
can_enable_irq(canDev, CAN_IER_TMEIE);
}
}

ENABLE_CAN_USER_INTERRUPTS();
}

Stm32Can* Stm32Can::GetInterface(int index)
{
Expand Down