Skip to content
Open
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
16 changes: 16 additions & 0 deletions STM32F1/cores/maple/HardwareTimer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,22 @@ uint16 HardwareTimer::setPeriod(uint32 microseconds) {
return overflow;
}

uint16 HardwareTimer::setCycles(uint32 Cycles) {
// Not the best way to handle this edge case?
if (!Cycles) {
this->setPrescaleFactor(1);
this->setOverflow(1);
return this->getOverflow();
}

uint32 period_cyc = Cycles;
uint16 prescaler = (uint16)(period_cyc / MAX_RELOAD + 1);
uint16 overflow = (uint16)((period_cyc + (prescaler / 2)) / prescaler);
this->setPrescaleFactor(prescaler);
this->setOverflow(overflow);
return overflow;
}

void HardwareTimer::setMode(int channel, timer_mode mode) {
timer_set_mode(this->dev, (uint8)channel, (timer_mode)mode);
}
Expand Down
12 changes: 12 additions & 0 deletions STM32F1/cores/maple/HardwareTimer.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,18 @@ class HardwareTimer {
*/
void setCount(uint16 val);

/**
* @brief Set the timer's period in Cycles.
*
* Configures the prescaler and overflow values to generate a timer
* reload with a period of given number of
* Cycles.
*
* @param Cycles The desired period of the timer. This must be
* greater than zero.
* @return The new overflow value.
*/
uint16 setCycles(uint32 Cycles);
/**
* @brief Set the timer's period in microseconds.
*
Expand Down
1 change: 1 addition & 0 deletions STM32F1/cores/maple/libmaple/rcc_f1.c
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ const struct rcc_dev_info rcc_dev_table[] = {
[RCC_TIMER13] = { .clk_domain = APB1, .line_num = 7 },
[RCC_TIMER14] = { .clk_domain = APB1, .line_num = 8 },
#endif
[RCC_CAN] = { .clk_domain = APB1, .line_num = 25 }, //! JMD after X893
};

__deprecated
Expand Down
15 changes: 15 additions & 0 deletions STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,25 @@ static void usb_resume(RESUME_STATE eResumeSetVal) {
}
}

// JMD : default ISRs of CAN, to be overridden if HardwareCAN library is used in sketch
void __attribute__((weak)) USB_HP_CAN_TX_IRQHandler(void)
{ ; } // Dummy ISR

void __irq_usb_hp_can_tx(void)
{
USB_HP_CAN_TX_IRQHandler () ;
}

uint8 __attribute__((weak)) CAN_RX0_IRQ_Handler(void)
{ return 0 ; } // Dummy ISR

#define SUSPEND_ENABLED 1
void __irq_usb_lp_can_rx0(void) {
uint16 istr = USB_BASE->ISTR;

if (CAN_RX0_IRQ_Handler()) //! JMD : Call to CAN ISR, returns 1 CAN is active
return; //! JMD

/* Use USB_ISR_MSK to only include code for bits we care about. */

#if (USB_ISR_MSK & USB_ISTR_RESET)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
#include <HardwareCAN.h>
/*
* Uses STM32duino with Phono patch. Must add 33 and 95 CAN speeds
*/
#define BPIN 0
#define SPIN 1
byte msgD0 ; // variable to be used in the example.

// Instanciation of CAN interface
HardwareCAN canBus(CAN1_BASE);
CanMsg msg ;

void CANSetup(void)
{
CAN_STATUS Stat ;

// Initialize CAN module
canBus.map(CAN_GPIO_PB8_PB9); // This setting is already wired in the Olimexino-STM32 board
Stat = canBus.begin(CAN_SPEED_95, CAN_MODE_NORMAL); // Other speeds go from 125 kbps to 1000 kbps. CAN allows even more choices.

canBus.filter(0, 0, 0);
canBus.set_irq_mode(); // Use irq mode (recommended), so the handling of incoming messages
// will be performed at ease in a task or in the loop. The software fifo is 16 cells long,
// allowing at least 15 ms before processing the fifo is needed at 125 kbps
Stat = canBus.status();
if (Stat != CAN_OK)
/* Your own error processing here */ ; // Initialization failed
}


// Send one frame. Parameter is a pointer to a frame structure (above), that has previously been updated with data.
// If no mailbox is available, wait until one becomes empty. There are 3 mailboxes.
CAN_TX_MBX CANsend(CanMsg *pmsg) // Should be moved to the library?!
{
CAN_TX_MBX mbx;

do
{
mbx = canBus.send(pmsg) ;
#ifdef USE_MULTITASK
vTaskDelay( 1 ) ; // Infinite loops are not multitasking-friendly
#endif
}
while(mbx == CAN_TX_NO_MBX) ; // Waiting outbound frames will eventually be sent, unless there is a CAN bus failure.
return mbx ;
}

// Send message
// Prepare and send a frame containing some value
void SendCANmessage(long id=0x001, byte dlength=8, byte d0=0x00, byte d1=0x00, byte d2=0x00, byte d3=0x00, byte d4=0x00, byte d5=0x00, byte d6=0x00, byte d7=0x00)
{
// Initialize the message structure
// A CAN structure includes the following fields:
msg.IDE = CAN_ID_STD; // Indicates a standard identifier ; CAN_ID_EXT would mean this frame uses an extended identifier
msg.RTR = CAN_RTR_DATA; // Indicated this is a data frame, as opposed to a remote frame (would then be CAN_RTR_REMOTE)
msg.ID = id ; // Identifier of the frame : 0-2047 (0-0x3ff) for standard idenfiers; 0-0x1fffffff for extended identifiers
msg.DLC = dlength; // Number of data bytes to follow

// Prepare frame : send something
msg.Data[0] = d0 ;
msg.Data[1] = d1 ;
msg.Data[2] = d2 ;
msg.Data[3] = d3 ;
msg.Data[4] = d4 ;
msg.Data[5] = d5 ;
msg.Data[6] = d6 ;
msg.Data[7] = d7 ;

digitalWrite(PC13, LOW); // turn the onboard LED on
CANsend(&msg) ; // Send this frame
delay(180);
digitalWrite(PC13, HIGH); // turn the LED off
delay(100);
}

// The application program starts here
int bState = 0; // variable for reading the pushbutton status
int sState = 0; // variable for reading the switch status
byte st = 0x31; // buttot 1 on the CD30MP3

void setup() {
// put your setup code here, to run once:
CANSetup() ; // Initialize the CAN module and prepare the message structures.
pinMode(PC13, OUTPUT);
pinMode(BPIN, INPUT); // input for hardware button
pinMode(SPIN, INPUT); // input for hardware switch
Serial1.begin(115200);
Serial1.println("Hello World!");
msgD0 = 0x01;
delay(500);
}

void loop() {
bState = digitalRead(BPIN);
sState = digitalRead(SPIN);
// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
if (bState == HIGH) {
long msgID = 0x201 ;
SendCANmessage(msgID, 3, 0x01, 0x6f, 0x00) ;
Serial1.println("OK pressed");
}

// check if the switch is high.
// if it is:
if (sState == HIGH) {
long msgID = 0x201 ;
SendCANmessage(msgID, 3, 0x01, st, 0x00) ;
Serial1.print("Station changed to ");
Serial1.println(st);
delay(500);
if (st == 0x39){st=0x31;} else {st++;};
}
// try to read message and output to serial
CanMsg *r_msg;
if ((r_msg = canBus.recv()) != NULL){
Serial1.print(r_msg->ID);
Serial1.print("#");
Serial1.print(r_msg->Data[0]);
Serial1.print(".");
Serial1.print(r_msg->Data[1]);
Serial1.print(".");
Serial1.print(r_msg->Data[2]);
Serial1.print(".");
Serial1.print(r_msg->Data[3]);
Serial1.print(".");
Serial1.print(r_msg->Data[4]);
Serial1.print(".");
Serial1.print(r_msg->Data[5]);
Serial1.print(".");
Serial1.print(r_msg->Data[6]);
Serial1.print(".");
Serial1.println(r_msg->Data[7]);
if (r_msg->ID == 0x201 and r_msg->Data[0] == 0x01 and r_msg->Data[1] == 0xFF){
// SETTINGS is pressed!
Serial1.println("SETTINGS. Pause for 2 seconds.");
digitalWrite(PC13, LOW); // turn the onboard LED on
delay(2000);
digitalWrite(PC13, HIGH); // turn the LED off
}
canBus.free();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#include <HardwareCAN.h>
//#include "changes.h"
/*
* Example of use of the HardwareCAN library
* This application sends two times one frame of data and then blinkes 3 times. Then repeats after 2 seconds.
* It also produces data that are sent periodically using another two frames.
*
* Please read the file changes.h to see the changes to be performed to the core in order to use this
*/

byte msgD0 ; // variable to be used in the example.

// Instanciation of CAN interface
HardwareCAN canBus(CAN1_BASE);
CanMsg msg ;

void CANSetup(void)
{
CAN_STATUS Stat ;

// Initialize CAN module
canBus.map(CAN_GPIO_PB8_PB9); // This setting is already wired in the Olimexino-STM32 board
Stat = canBus.begin(CAN_SPEED_125, CAN_MODE_NORMAL); // Other speeds go from 125 kbps to 1000 kbps. CAN allows even more choices.

canBus.filter(0, 0, 0);
canBus.set_irq_mode(); // Use irq mode (recommended), so the handling of incoming messages
// will be performed at ease in a task or in the loop. The software fifo is 16 cells long,
// allowing at least 15 ms before processing the fifo is needed at 125 kbps
Stat = canBus.status();
if (Stat != CAN_OK)
/* Your own error processing here */ ; // Initialization failed
}


// Send one frame. Parameter is a pointer to a frame structure (above), that has previously been updated with data.
// If no mailbox is available, wait until one becomes empty. There are 3 mailboxes.
CAN_TX_MBX CANsend(CanMsg *pmsg) // Should be moved to the library?!
{
CAN_TX_MBX mbx;

do
{
mbx = canBus.send(pmsg) ;
#ifdef USE_MULTITASK
vTaskDelay( 1 ) ; // Infinite loops are not multitasking-friendly
#endif
}
while(mbx == CAN_TX_NO_MBX) ; // Waiting outbound frames will eventually be sent, unless there is a CAN bus failure.
return mbx ;
}

// Send message
// Prepare and send a frame containing some value
void SendCANmessage(long id=0x001, byte d0=0x00, byte d1=0x00, byte d2=0x00, byte d3=0x00, byte d4=0x00, byte d5=0x00, byte d6=0x00, byte d7=0x00)
{
// Initialize the message structure
// A CAN structure includes the following fields:
msg.IDE = CAN_ID_STD; // Indicates a standard identifier ; CAN_ID_EXT would mean this frame uses an extended identifier
msg.RTR = CAN_RTR_DATA; // Indicated this is a data frame, as opposed to a remote frame (would then be CAN_RTR_REMOTE)
msg.ID = id ; // Identifier of the frame : 0-2047 (0-0x3ff) for standard idenfiers; 0-0x1fffffff for extended identifiers
msg.DLC = 8; // Number of data bytes to follow

// Prepare frame : send something
msg.Data[0] = d0 ;
msg.Data[1] = d1 ;
msg.Data[2] = d2 ;
msg.Data[3] = d3 ;
msg.Data[4] = d4 ;
msg.Data[5] = d5 ;
msg.Data[6] = d6 ;
msg.Data[7] = d7 ;

digitalWrite(PC13, LOW); // turn the onboard LED on
CANsend(&msg) ; // Send this frame
delay(180);
digitalWrite(PC13, HIGH); // turn the LED off
delay(100);
}

// The application program starts here
void setup() {
// put your setup code here, to run once:
CANSetup() ; // Initialize the CAN module and prepare the message structures.
pinMode(PC13, OUTPUT);
msgD0 = 0x01;
}

void loop() {
delay(1000);
long msgID = 0x101 ;
SendCANmessage(msgID, msgD0) ;
msgD0++;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifdef CHANGES_INCLUDE

****** DETAILS OF THE CHANGES TO BE DONE TO THE CORE TO BE ABLE TO USE THE LIBRARY HardwareCAN ******

1) History
The Hardware CAN library was originally published in the Maple Leaflabs forum by X893.
I tested it, and found bugs, which I fixed in the code. My fixes are commented with the initials JMD.
The most important things that missed was to connect the interrupt service routine to the CAN interrupt vector.
The problem is that in the F1 family, this vector is shared with the USB vector, as is some of the memory. Thus,
when one wants to use the CAN, the USB becomes unavailable. This is a severe drawback of this chip, but one has to cope with this.

2) Changes performed

2.1) In file C:\ArduinoForSTM32\arduino-1.6.9\hardware\Arduino_STM32-master\STM32F1\cores\maple\libmaple\rcc_f1.c
inserted 1 line, position 96:
[RCC_CAN] = { .clk_domain = APB1, .line_num = 25 }, //! JMD after X893

2.2) In file C:\ArduinoForSTM32\arduino-1.6.9\hardware\Arduino_STM32-master\STM32F1\system\libmaple\stm32f1\include\series\rcc.h
inserted 1 line, position 442:
RCC_CAN, //! JMD after X893

2.3) In file C:\ArduinoForSTM32\arduino-1.6.9\hardware\Arduino_STM32-master\STM32F1\cores\maple\libmaple\usb\stm32f1\usb.c
2.3.1) inserted 12 lines, position 186
// JMD : default ISRs of CAN, to be overridden if HardwareCAN library is used in sketch
void __attribute__((weak)) USB_HP_CAN_TX_IRQHandler(void)
{ ; } // Dummy ISR

void __irq_usb_hp_can_tx(void)
{
USB_HP_CAN_TX_IRQHandler () ;
}

uint8 __attribute__((weak)) CAN_RX0_IRQ_Handler(void)
{ return 1 ; } // Dummy ISR

2.3.2) and altered function void __irq_usb_lp_can_rx0(void)
Was

void __irq_usb_lp_can_rx0(void) {
uint16 istr = USB_BASE->ISTR;

/* Use USB_ISR_MSK to only include code for bits we care about. */

Becomes

void __irq_usb_lp_can_rx0(void) {
uint16 istr = USB_BASE->ISTR;

if (CAN_RX0_IRQ_Handler()) //! JMD : Call to CAN ISR, returns 1 CAN is active
return; //! JMD

/* Use USB_ISR_MSK to only include code for bits we care about. */
#endif
Loading