Skip to content

Commit

Permalink
Merge pull request #12 from HamedJafarzadeh/master
Browse files Browse the repository at this point in the history
STM32 Library overhaul
  • Loading branch information
MaJerle authored Oct 18, 2022
2 parents e615e1a + b084ab2 commit c7fb1de
Show file tree
Hide file tree
Showing 960 changed files with 635,290 additions and 21,433 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
*.__i
*.i
*.txt
*.launch
!docs/*.txt
RTE/

Expand Down
21 changes: 9 additions & 12 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -1,16 +1,13 @@
[submodule "libs/lwrb"]
path = libs/lwrb
[submodule "legacy/libs/lwmem"]
path = legacy/libs/lwmem
url = https://github.com/MaJerle/lwmem
[submodule "legacy/libs/lwprintf"]
path = legacy/libs/lwprintf
url = https://github.com/MaJerle/lwprintf
[submodule "legacy/libs/lwrb"]
path = legacy/libs/lwrb
url = https://github.com/MaJerle/lwrb
branch = master
[submodule "CANopenNode"]
path = CANopenNode
url = https://github.com/CANopenNode/CANopenNode
branch = master
[submodule "libs/lwprintf"]
path = libs/lwprintf
url = https://github.com/MaJerle/lwprintf
branch = master
[submodule "libs/lwmem"]
path = libs/lwmem
url = https://github.com/MaJerle/lwmem
branch = master
branch = master
2 changes: 2 additions & 0 deletions CANopenNode_STM32/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
OD.c
OD.h
251 changes: 251 additions & 0 deletions CANopenNode_STM32/CO_app_STM32.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
/*
* CANopen main program file.
*
* This file is a template for other microcontrollers.
*
* @file main_generic.c
* @author Hamed Jafarzadeh 2022
* Janez Paternoster 2021
* @copyright 2021 Janez Paternoster
*
* This file is part of CANopenNode, an opensource CANopen Stack.
* Project home page is <https://github.com/CANopenNode/CANopenNode>.
* For more information on CANopen see <http://www.can-cia.org/>.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "CO_app_STM32.h"
#include "CANopen.h"
#include "main.h"
#include <stdio.h>

#include "CO_storageBlank.h"
#include "OD.h"

CANopenNodeSTM32*
canopenNodeSTM32; // It will be set by canopen_app_init and will be used across app to get access to CANOpen objects

/* Printf function of CanOpen app */
#define log_printf(macropar_message, ...) printf(macropar_message, ##__VA_ARGS__)

/* default values for CO_CANopenInit() */
#define NMT_CONTROL \
CO_NMT_STARTUP_TO_OPERATIONAL \
| CO_NMT_ERR_ON_ERR_REG | CO_ERR_REG_GENERIC_ERR | CO_ERR_REG_COMMUNICATION
#define FIRST_HB_TIME 500
#define SDO_SRV_TIMEOUT_TIME 1000
#define SDO_CLI_TIMEOUT_TIME 500
#define SDO_CLI_BLOCK false
#define OD_STATUS_BITS NULL

/* Global variables and objects */
CO_t* CO = NULL; /* CANopen object */

// Global variables
uint32_t time_old, time_current;
CO_ReturnError_t err;

/* This function will basically setup the CANopen node */
int
canopen_app_init(CANopenNodeSTM32* _canopenNodeSTM32) {

// Keep a copy global reference of canOpenSTM32 Object
canopenNodeSTM32 = _canopenNodeSTM32;

#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE
CO_storage_t storage;
CO_storage_entry_t storageEntries[] = {{.addr = &OD_PERSIST_COMM,
.len = sizeof(OD_PERSIST_COMM),
.subIndexOD = 2,
.attr = CO_storage_cmd | CO_storage_restore,
.addrNV = NULL}};
uint8_t storageEntriesCount = sizeof(storageEntries) / sizeof(storageEntries[0]);
uint32_t storageInitError = 0;
#endif

/* Allocate memory */
CO_config_t* config_ptr = NULL;
#ifdef CO_MULTIPLE_OD
/* example usage of CO_MULTIPLE_OD (but still single OD here) */
CO_config_t co_config = {0};
OD_INIT_CONFIG(co_config); /* helper macro from OD.h */
co_config.CNT_LEDS = 1;
co_config.CNT_LSS_SLV = 1;
config_ptr = &co_config;
#endif /* CO_MULTIPLE_OD */

uint32_t heapMemoryUsed;
CO = CO_new(config_ptr, &heapMemoryUsed);
if (CO == NULL) {
log_printf("Error: Can't allocate memory\n");
return 1;
} else {
log_printf("Allocated %u bytes for CANopen objects\n", heapMemoryUsed);
}

canopenNodeSTM32->canOpenStack = CO;

#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE
err = CO_storageBlank_init(&storage, CO->CANmodule, OD_ENTRY_H1010_storeParameters,
OD_ENTRY_H1011_restoreDefaultParameters, storageEntries, storageEntriesCount,
&storageInitError);

if (err != CO_ERROR_NO && err != CO_ERROR_DATA_CORRUPT) {
log_printf("Error: Storage %d\n", storageInitError);
return 2;
}
#endif

canopen_app_resetCommunication();
return 0;
}

int
canopen_app_resetCommunication() {
/* CANopen communication reset - initialize CANopen objects *******************/
log_printf("CANopenNode - Reset communication...\n");

/* Wait rt_thread. */
CO->CANmodule->CANnormal = false;

/* Enter CAN configuration. */
CO_CANsetConfigurationMode((void*)canopenNodeSTM32);
CO_CANmodule_disable(CO->CANmodule);

/* initialize CANopen */
err = CO_CANinit(CO, canopenNodeSTM32, 0); // Bitrate for STM32 microcontroller is being set in MXCube Settings
if (err != CO_ERROR_NO) {
log_printf("Error: CAN initialization failed: %d\n", err);
return 1;
}

CO_LSS_address_t lssAddress = {.identity = {.vendorID = OD_PERSIST_COMM.x1018_identity.vendor_ID,
.productCode = OD_PERSIST_COMM.x1018_identity.productCode,
.revisionNumber = OD_PERSIST_COMM.x1018_identity.revisionNumber,
.serialNumber = OD_PERSIST_COMM.x1018_identity.serialNumber}};
err = CO_LSSinit(CO, &lssAddress, &canopenNodeSTM32->desiredNodeID, &canopenNodeSTM32->baudrate);
if (err != CO_ERROR_NO) {
log_printf("Error: LSS slave initialization failed: %d\n", err);
return 2;
}

canopenNodeSTM32->activeNodeID = canopenNodeSTM32->desiredNodeID;
uint32_t errInfo = 0;

err = CO_CANopenInit(CO, /* CANopen object */
NULL, /* alternate NMT */
NULL, /* alternate em */
OD, /* Object dictionary */
OD_STATUS_BITS, /* Optional OD_statusBits */
NMT_CONTROL, /* CO_NMT_control_t */
FIRST_HB_TIME, /* firstHBTime_ms */
SDO_SRV_TIMEOUT_TIME, /* SDOserverTimeoutTime_ms */
SDO_CLI_TIMEOUT_TIME, /* SDOclientTimeoutTime_ms */
SDO_CLI_BLOCK, /* SDOclientBlockTransfer */
canopenNodeSTM32->activeNodeID, &errInfo);
if (err != CO_ERROR_NO && err != CO_ERROR_NODE_ID_UNCONFIGURED_LSS) {
if (err == CO_ERROR_OD_PARAMETERS) {
log_printf("Error: Object Dictionary entry 0x%X\n", errInfo);
} else {
log_printf("Error: CANopen initialization failed: %d\n", err);
}
return 3;
}

err = CO_CANopenInitPDO(CO, CO->em, OD, canopenNodeSTM32->activeNodeID, &errInfo);
if (err != CO_ERROR_NO) {
if (err == CO_ERROR_OD_PARAMETERS) {
log_printf("Error: Object Dictionary entry 0x%X\n", errInfo);
} else {
log_printf("Error: PDO initialization failed: %d\n", err);
}
return 4;
}

/* Configure Timer interrupt function for execution every 1 millisecond */
HAL_TIM_Base_Start_IT(canopenNodeSTM32->timerHandle); //1ms interrupt

/* Configure CAN transmit and receive interrupt */

/* Configure CANopen callbacks, etc */
if (!CO->nodeIdUnconfigured) {

#if (CO_CONFIG_STORAGE) & CO_CONFIG_STORAGE_ENABLE
if (storageInitError != 0) {
CO_errorReport(CO->em, CO_EM_NON_VOLATILE_MEMORY, CO_EMC_HARDWARE, storageInitError);
}
#endif
} else {
log_printf("CANopenNode - Node-id not initialized\n");
}

/* start CAN */
CO_CANsetNormalMode(CO->CANmodule);

log_printf("CANopenNode - Running...\n");
fflush(stdout);
time_old = time_current = HAL_GetTick();
return 0;
}

void
canopen_app_process() {
/* loop for normal program execution ******************************************/
/* get time difference since last function call */
time_current = HAL_GetTick();

if ((time_current - time_old) > 0) { // Make sure more than 1ms elapsed
/* CANopen process */
CO_NMT_reset_cmd_t reset_status;
uint32_t timeDifference_us = (time_current - time_old) * 1000;
time_old = time_current;
reset_status = CO_process(CO, false, timeDifference_us, NULL);
canopenNodeSTM32->outStatusLEDRed = CO_LED_RED(CO->LEDs, CO_LED_CANopen);
canopenNodeSTM32->outStatusLEDGreen = CO_LED_GREEN(CO->LEDs, CO_LED_CANopen);

if (reset_status == CO_RESET_COMM) {
/* delete objects from memory */
CO_CANsetConfigurationMode((void*)canopenNodeSTM32);
CO_delete(CO);
log_printf("CANopenNode Reset Communication request\n");
canopen_app_resetCommunication(); // Reset Communication routine
} else if (reset_status == CO_RESET_APP) {
log_printf("CANopenNode Device Reset\n");
HAL_NVIC_SystemReset(); // Reset the STM32 Microcontroller
}
}
}

/* Thread function executes in constant intervals, this function can be called from FreeRTOS tasks or Timers ********/
void
canopen_app_interrupt(void) {
CO_LOCK_OD(CO->CANmodule);
if (!CO->nodeIdUnconfigured && CO->CANmodule->CANnormal) {
bool_t syncWas = false;
/* get time difference since last function call */
uint32_t timeDifference_us = 1000; // 1ms second

#if (CO_CONFIG_SYNC) & CO_CONFIG_SYNC_ENABLE
syncWas = CO_process_SYNC(CO, timeDifference_us, NULL);
#endif
#if (CO_CONFIG_PDO) & CO_CONFIG_RPDO_ENABLE
CO_process_RPDO(CO, syncWas, timeDifference_us, NULL);
#endif
#if (CO_CONFIG_PDO) & CO_CONFIG_TPDO_ENABLE
CO_process_TPDO(CO, syncWas, timeDifference_us, NULL);
#endif

/* Further I/O or nonblocking application code may go here. */
}
CO_UNLOCK_OD(CO->CANmodule);
}
74 changes: 74 additions & 0 deletions CANopenNode_STM32/CO_app_STM32.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
* CO_app_STM32.h
*
* Created on: Aug 7, 2022
* Author: hamed
*/

#ifndef CANOPENSTM32_CO_APP_STM32_H_
#define CANOPENSTM32_CO_APP_STM32_H_

#include "CANopen.h"
#include "main.h"

/* CANHandle : Pass in the CAN Handle to this function and it wil be used for all CAN Communications. It can be FDCan or CAN
* and CANOpenSTM32 Driver will take of care of handling that
* HWInitFunction : Pass in the function that initialize the CAN peripheral, usually MX_CAN_Init
* timerHandle : Pass in the timer that is going to be used for generating 1ms interrupt for tmrThread function,
* please note that CANOpenSTM32 Library will override HAL_TIM_PeriodElapsedCallback function, if you also need this function
* in your codes, please take required steps
*/

#ifdef __cplusplus
extern "C" {
#endif


typedef struct {
uint8_t
desiredNodeID; /*This is the Node ID that you ask the CANOpen stack to assign to your device, although it might not always
* be the final NodeID, after calling canopen_app_init() you should check ActiveNodeID of CANopenNodeSTM32 structure for assigned Node ID.
*/
uint8_t activeNodeID; /* Assigned Node ID */
uint8_t baudrate; /* This is the baudrate you've set in your CubeMX Configuration */
TIM_HandleTypeDef*
timerHandle; /*Pass in the timer that is going to be used for generating 1ms interrupt for tmrThread function,
* please note that CANOpenSTM32 Library will override HAL_TIM_PeriodElapsedCallback function, if you also need this function in your codes, please take required steps
*/

/* Pass in the CAN Handle to this function and it wil be used for all CAN Communications. It can be FDCan or CAN
* and CANOpenSTM32 Driver will take of care of handling that*/
#ifdef CO_STM32_FDCAN_Driver
FDCAN_HandleTypeDef* CANHandle;
#else
CAN_HandleTypeDef* CANHandle;
#endif

void (*HWInitFunction)(); /* Pass in the function that initialize the CAN peripheral, usually MX_CAN_Init */

uint8_t outStatusLEDGreen; // This will be updated by the stack - Use them for the LED management
uint8_t outStatusLEDRed; // This will be updated by the stack - Use them for the LED management
CO_t* canOpenStack;

} CANopenNodeSTM32;


// In order to use CANOpenSTM32, you'll have it have a canopenNodeSTM32 structure somewhere in your codes, it is usually residing in CO_app_STM32.c
extern CANopenNodeSTM32* canopenNodeSTM32;


/* This function will initialize the required CANOpen Stack objects, allocate the memory and prepare stack for communication reset*/
int canopen_app_init(CANopenNodeSTM32* canopenSTM32);
/* This function will reset the CAN communication periperhal and also the CANOpen stack variables */
int canopen_app_resetCommunication();
/* This function will check the input buffers and any outstanding tasks that are not time critical, this function should be called regurarly from your code (i.e from your while(1))*/
void canopen_app_process();
/* Thread function executes in constant intervals, this function can be called from FreeRTOS tasks or Timers ********/
void canopen_app_interrupt(void);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* CANOPENSTM32_CO_APP_STM32_H_ */
Loading

0 comments on commit c7fb1de

Please sign in to comment.