From 49d5ed2f2e357c34f568b6cec297fc62da7995c4 Mon Sep 17 00:00:00 2001 From: Phonog Date: Mon, 31 Oct 2016 22:21:27 +0100 Subject: [PATCH 01/18] Add files via upload --- .../examples/HardwareCANexample/Changes.h | 53 ++ .../HardwareCANexample/HardwareCANexample.ino | 181 +++++ STM32F1/libraries/HardwareCAN/keywords.txt | 40 ++ .../libraries/HardwareCAN/library.properties | 9 + .../libraries/HardwareCAN/src/HardwareCAN.cpp | 120 ++++ .../libraries/HardwareCAN/src/HardwareCAN.h | 68 ++ .../libraries/HardwareCAN/src/utility/can.c | 543 +++++++++++++++ .../libraries/HardwareCAN/src/utility/can.h | 322 +++++++++ STM32F1/libraries/rcc.h | 641 ++++++++++++++++++ STM32F1/libraries/rcc_f1.c | 174 +++++ STM32F1/libraries/usb.c | 402 +++++++++++ 11 files changed, 2553 insertions(+) create mode 100644 STM32F1/libraries/HardwareCAN/examples/HardwareCANexample/Changes.h create mode 100644 STM32F1/libraries/HardwareCAN/examples/HardwareCANexample/HardwareCANexample.ino create mode 100644 STM32F1/libraries/HardwareCAN/keywords.txt create mode 100644 STM32F1/libraries/HardwareCAN/library.properties create mode 100644 STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp create mode 100644 STM32F1/libraries/HardwareCAN/src/HardwareCAN.h create mode 100644 STM32F1/libraries/HardwareCAN/src/utility/can.c create mode 100644 STM32F1/libraries/HardwareCAN/src/utility/can.h create mode 100644 STM32F1/libraries/rcc.h create mode 100644 STM32F1/libraries/rcc_f1.c create mode 100644 STM32F1/libraries/usb.c diff --git a/STM32F1/libraries/HardwareCAN/examples/HardwareCANexample/Changes.h b/STM32F1/libraries/HardwareCAN/examples/HardwareCANexample/Changes.h new file mode 100644 index 000000000..1ccd2fe88 --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/examples/HardwareCANexample/Changes.h @@ -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 diff --git a/STM32F1/libraries/HardwareCAN/examples/HardwareCANexample/HardwareCANexample.ino b/STM32F1/libraries/HardwareCAN/examples/HardwareCANexample/HardwareCANexample.ino new file mode 100644 index 000000000..4e3a9e574 --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/examples/HardwareCANexample/HardwareCANexample.ino @@ -0,0 +1,181 @@ +#include +#include "changes.h" +/* + * Example of use of the HardwareCAN library + * This application receives two frames containing various data. 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 + */ +// Define the values of the identifiers +#define GYRO_ID 0x27 +#define JOYSTICK_VALUES_ID 0x5A +#define TANK_LEVEL_ID 0x78 +#define MOTOR_CONTROL_ID 0x92 + +// Limit time to flag a CAN error +#define CAN_TIMEOUT 100 +#define CAN_DELAY 10 // ms between two processings of incoming messages +#define CAN_SEND_RATE 200 // ms between two successive sendings + +// Message structures. Each message has its own identifier. As many such variables should be defined +// as the number of different CAN frames the application has to send. Here, they are two. +CanMsg msgGyroscope ; +CanMsg msgMotorControl ; + +// Traffic handling data +int CANquietTime ; // Quiet time counter to detect no activity on CAN bus +bool CANError ; // Indicates that incoming CAN traffic is missing +int CANsendDivider ; // Used to send frames once every so many times loop() is called + +// Applicaton variables +int Contents[4] ; // Contents of the four tanks +int JoystickX ; // Setting of the joystick, X axis +int JoystickY ; // ... Y axis +int AngularRate ; // Output of local gyroscope +int Throttle ; // Motor control value, produced by some local processing +bool ErreurGyroscope = false ; + +// Instanciation of CAN interface +HardwareCAN canBus(CAN1_BASE); + + +// Note : for the predefined identifiers, please have a look in file can.h + +void CANSetup(void) +{ + CAN_STATUS Stat ; + + // Initialize the message structures + // A CAN structure includes the following fields: + msgGyroscope.IDE = CAN_ID_STD; // Indicates a standard identifier ; CAN_ID_EXT would mean this frame uses an extended identifier + msgGyroscope.RTR = CAN_RTR_DATA; // Indicated this is a data frame, as opposed to a remote frame (would then be CAN_RTR_REMOTE) + msgGyroscope.ID = GYRO_ID ; // Identifier of the frame : 0-2047 (0-0x3ff) for standard idenfiers; 0-0x1fffffff for extended identifiers + msgGyroscope.DLC = 3; // Number of data bytes to follow + msgGyroscope.Data[0] = 0x0; // Data bytes, there can be 0 to 8 bytes. + msgGyroscope.Data[1] = 0x0; + msgGyroscope.Data[2] = 0x0; + + msgMotorControl.IDE = CAN_ID_STD; + msgMotorControl.RTR = CAN_RTR_DATA; + msgMotorControl.ID = MOTOR_CONTROL_ID ; + msgMotorControl.DLC = 2; + msgMotorControl.Data[0] = 0x0; + msgMotorControl.Data[1] = 0x0; + + // 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) +{ + 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 ; +} + +// Process incoming messages +// Note : frames are not fully checked for correctness: DLC value is not checked, neither are the IDE and RTR fields. However, the data is guaranteed to be corrrect. +void ProcessMessages(void) +{ + int Pr = 0 ; + int i ; + + CanMsg *r_msg; + + // Loop for every message in the fifo + while ((r_msg = canBus.recv()) != NULL) + { + CANquietTime = 0 ; // Reset at each received frame + CANError = false ; // Clear CAN silence error + switch ( r_msg->ID ) + { + case TANK_LEVEL_ID : // This frame contains four 16-bit words, little endian coded + for ( i = 0 ; i < 4 ; i++ ) + Contents[i] = (int)r_msg->Data[2*i] | ((int)r_msg->Data[(2*i)+1]) << 8 ; + break ; + + case JOYSTICK_VALUES_ID : // This frame contains two 16-bit words, little endian coded + Pr = (int)r_msg->Data[0] ; + Pr |= (int)r_msg->Data[1] << 8 ; + JoystickX = Pr ; + + Pr = (int)r_msg->Data[2] ; + Pr |= (int)r_msg->Data[3] << 8 ; + JoystickY = Pr ; + break ; + + default : // Any frame with a different identifier is ignored + break ; + } + + canBus.free(); // Remove processed message from buffer, whatever the identifier +#ifdef USE_MULTITASK + vTaskDelay( 1 ) ; // Infinite loops are not multitasking-friendly +#endif + } +} + +// Send messages +// Prepare and send 2 frames containing the value of process variables +// Sending all frames at once is a choice; they could be sent separately, at different times and rates. +void SendCANmessages(void) +{ + // Prepare Gyroscope frame : send angular rate + msgGyroscope.Data[0] = AngularRate & 0xff ; + msgGyroscope.Data[1] = ( AngularRate >> 8 ) & 0xff ; + msgGyroscope.Data[2] = ErreurGyroscope ? 1 : 0 ; + CANsend(&msgGyroscope) ; // Send this frame + + msgMotorControl.Data[0] = Throttle & 0xff ; + msgMotorControl.Data[1] = ( Throttle >> 8 ) & 0xff ; + CANsend(&msgMotorControl) ; +} + +// 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. +} + +void loop() { + // Process incoming messages periodically (should be often enough to avoid overflowing the fifo) + ProcessMessages() ; // Process all incoming messages, update local variables accordingly + + // This is an example of timeout management. Here it is global to all received frames; + // it could be on a frame by frame basis, with as many control variables as the number of frames. + CANquietTime++ ; + if ( CANquietTime > CAN_TIMEOUT ) + { + CANquietTime = CAN_TIMEOUT + 1 ; // To prevent overflowing this variable if silence prolongs... + CANError = true ; // Flag CAN silence error. Will be cleared at first frame received + } + + // Send messages containing variables to publish. Sent less frequently than the processing of incoming frames (here, every 200 ms) + CANsendDivider-- ; + if ( CANsendDivider < 0 ) + { + CANsendDivider = CAN_SEND_RATE / CAN_DELAY ; + SendCANmessages() ; + } + delay(CAN_DELAY) ; // The delay must not be greater than the time to overflow the incoming fifo (here about 15 ms) +} + + diff --git a/STM32F1/libraries/HardwareCAN/keywords.txt b/STM32F1/libraries/HardwareCAN/keywords.txt new file mode 100644 index 000000000..6d901e314 --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/keywords.txt @@ -0,0 +1,40 @@ +####################################### +# Syntax Coloring Map For HardwareCAN +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### +HardwareCAN KEYWORD1 +CanMsg KEYWORD1 +CAN_TX_MBX KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### +release KEYWORD2 CAN_Release +send KEYWORD2 CAN_Send +read KEYWORD2 CAN_Read +recv KEYWORD2 CAN_Recieve +set_pool_mode KEYWORD2 CAN_Set_Pool_Mode +set_irq_mode KEYWORD2 CAN_Set_IRQ_Mode +fifo_ready KEYWORD2 CAN_Fifo_Ready +filter KEYWORD2 CAN_Filter +free KEYWORD2 CAN_Free +available KEYWORD2 CAN_Available + +####################################### +# Constants (LITERAL1) +####################################### +CAN_GPIO_PD0_PD1 LITERAL1 +CAN_GPIO_PB8_PB9 LITERAL1 +CAN_FIFO0 LITERAL1 +CAN_FIFO1 LITERAL1 +CAN_SPEED_125 LITERAL1 +CAN_SPEED_250 LITERAL1 +CAN_SPEED_500 LITERAL1 +CAN_SPEED_1000 LITERAL1 +CAN1_BASE LITERAL1 +CAN2_BASE LITERAL1 +CAN_ID_STD LITERAL1 +CAN_RTR_DATA LITERAL1 diff --git a/STM32F1/libraries/HardwareCAN/library.properties b/STM32F1/libraries/HardwareCAN/library.properties new file mode 100644 index 000000000..9186eb6cc --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/library.properties @@ -0,0 +1,9 @@ +name=HardwareCAN +version=1.0.0 +author=Maple Leaflabs fixed by JMD +maintainer=JMD +sentence=Enables managing CAN communication using the built-in CAN port of the OLIMEX STM32 board. +paragraph=With this library you can use the built-in CAN port of the OLIMEX STM32. The library handles both standard and extended frames. +category=Communication +url= +architectures=* \ No newline at end of file diff --git a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp new file mode 100644 index 000000000..f113c4d85 --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp @@ -0,0 +1,120 @@ +/** + * @brief HardwareCAN "wiring-like" api for CAN + */ + +#include "wirish.h" +#include "utility/can.h" +#include "HardwareCAN.h" + +/** + * @brief Initialize a CAN peripheral + * @param freq frequency to run at, must one of the following values: + * - CAN_SPEED_1000 + * - CAN_SPEED_500 + * - CAN_SPEED_250 + * - CAN_SPEED_125 + */ +CAN_STATUS HardwareCAN::begin(CAN_SPEED speed, uint32 mode) +{ +/* Begin Fix JMD + if (can_init(Port, CAN_MCR_NART, CAN_SPEED_250) == CAN_OK) + // NART empêche la réémission en cas de perte d'arbitrage d'où trames perdues + */ + Serial.end(); // disable USB interface -- JMD + if (can_init(Port, 0, speed) == CAN_OK) + // End Fix JMD + return can_set_mode(Port, mode); + return can_status(); +} + +void HardwareCAN::set_pool_mode(void) +{ + return can_set_pool_mode(Port); +} + +void HardwareCAN::set_irq_mode(void) +{ + return can_set_irq_mode(Port); +} + +CAN_STATUS HardwareCAN::filter(uint8 idx, uint32 id, uint32 mask) +{ + return can_filter(Port, idx, CAN_FIFO0, CAN_FILTER_32BIT, CAN_FILTER_MASK, id, mask); +} + +CAN_STATUS HardwareCAN::status(void) +{ + return can_status(); +} + +CAN_TX_MBX HardwareCAN::send(CanMsg* message) +{ + return can_transmit(Port, message); +} + +uint8 HardwareCAN::available(void) +{ + return can_rx_available(); +} + +CanMsg* HardwareCAN::recv(void) +{ + return can_rx_queue_get(); +} + +void HardwareCAN::clear(void) +{ + can_rx_queue_clear(); +} + +void HardwareCAN::free(void) +{ + can_rx_queue_free(); +} + +void HardwareCAN::cancel(CAN_TX_MBX mbx) +{ + can_cancel(Port, mbx); +} + +/** + * @brief Initialize a CAN peripheral + */ +CAN_STATUS HardwareCAN::begin(void) +{ + return begin(CAN_SPEED_250, CAN_MODE_NORMAL); +} + +void HardwareCAN::end(void) +{ + can_deinit(Port); +} + +CanMsg* HardwareCAN::read(CAN_FIFO fifo, CanMsg* msg) +{ + return can_read(Port, fifo, msg); +} + +void HardwareCAN::release(CAN_FIFO fifo) +{ + can_rx_release(Port, fifo); +} + +/** + * @brief Initialize a CAN peripheral + */ +CAN_STATUS HardwareCAN::map(CAN_GPIO_MAP remap) +{ + return can_gpio_map(Port, remap); +} + +uint8 HardwareCAN::fifo_ready(CAN_FIFO fifo) +{ + return can_fifo_ready(Port, fifo); +} + +HardwareCAN::HardwareCAN(CAN_Port* CANx) +{ + Port = CANx; +} + diff --git a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.h b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.h new file mode 100644 index 000000000..ccc318f5b --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.h @@ -0,0 +1,68 @@ +/** + * @brief HardwareCAN definitions + */ + +#ifndef _HARDWARECAN_H_ +#define _HARDWARECAN_H_ + +#include "utility/can.h" +#include "usb_serial.h" + +#define PID_REQUEST 0x7DF +#define PID_REPLY 0x7E8 + +#define ENGINE_COOLANT_TEMP 0x05 +#define ENGINE_RPM 0x0C +#define VEHICLE_SPEED 0x0D +#define MAF_SENSOR 0x10 +#define O2_VOLTAGE 0x14 +#define THROTTLE 0x11 + +/** + * Defines the possible SPI communication speeds. + */ + +class HardwareCAN +{ +private: +public: + CAN_Port* Port; + HardwareCAN(CAN_Port *CANx_BASE); + CAN_STATUS begin(void); + + uint32 MSR(void) + { + return Port->MSR; + } + + uint32 RF0R(void) + { + return Port->RF0R; + } + + void set_pool_mode(void); + void set_irq_mode(void); + + CAN_STATUS begin(CAN_SPEED speed, uint32 mode); + void end(void); + + CAN_STATUS filter(uint8 idx, uint32 id, uint32 mask); + CAN_STATUS map(CAN_GPIO_MAP remap); + CAN_STATUS status(void); + + CAN_TX_MBX send(CanMsg* message); + void cancel(CAN_TX_MBX mbx); + + uint8 available(void); + + CanMsg* recv(void); + + void free(void); + void clear(void); + + uint8 fifo_ready(CAN_FIFO fifo); + CanMsg* read(CAN_FIFO fifo, CanMsg* msg); + void release(CAN_FIFO fifo); +}; + +#endif diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.c b/STM32F1/libraries/HardwareCAN/src/utility/can.c new file mode 100644 index 000000000..0120e0eed --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.c @@ -0,0 +1,543 @@ +//#include "libmaple.h" +#include "can.h" +//#include "rcc.h" +//#include "gpio.h" +//#include "nvic.h" +//#include "usb.h" + +/** + * CAN_interrupts + */ + +#define CAN_IT_RQCP0 ((uint32)0x00000005) /* Request completed mailbox 0 */ +#define CAN_IT_RQCP1 ((uint32)0x00000006) /* Request completed mailbox 1 */ +#define CAN_IT_RQCP2 ((uint32)0x00000007) /* Request completed mailbox 2 */ +#define CAN_IT_TME ((uint32)0x00000001) /* Transmit mailbox empty */ +#define CAN_IT_FMP0 ((uint32)0x00000002) /* FIFO 0 message pending */ +#define CAN_IT_FF0 ((uint32)0x00000004) /* FIFO 0 full */ +#define CAN_IT_FOV0 ((uint32)0x00000008) /* FIFO 0 overrun */ +#define CAN_IT_FMP1 ((uint32)0x00000010) /* FIFO 1 message pending */ +#define CAN_IT_FF1 ((uint32)0x00000020) /* FIFO 1 full */ +#define CAN_IT_FOV1 ((uint32)0x00000040) /* FIFO 1 overrun */ +#define CAN_IT_EWG ((uint32)0x00000100) /* Error warning */ +#define CAN_IT_EPV ((uint32)0x00000200) /* Error passive */ +#define CAN_IT_BOF ((uint32)0x00000400) /* Bus-off */ +#define CAN_IT_LEC ((uint32)0x00000800) /* Last error code */ +#define CAN_IT_ERR ((uint32)0x00008000) /* Error */ +#define CAN_IT_WKU ((uint32)0x00010000) /* Wake-up */ +#define CAN_IT_SLK ((uint32)0x00020000) /* Sleep */ + +/* Time out for INAK bit */ +#define CAN_INAK_TimeOut ((uint32)0x0000FFFF) + +/* Time out for SLAK bit */ +#define CAN_SLAK_TimeOut ((uint32)0x0000FFFF) + +#define CAN_CONTROL_MASK (CAN_MCR_TTCM | CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_NART | CAN_MCR_RFLM | CAN_MCR_TXFP) +#define CAN_TIMING_MASK (CAN_BTR_SJW | CAN_BTR_TS2 | CAN_BTR_TS1 | CAN_BTR_BRP) +#define CAN_MODE_MASK (CAN_BTR_LBKM | CAN_BTR_SILM) + +struct can_speed_info { + const uint32 btr; +}; + +#define CAN_CLOCK (36000000UL / 18UL) + +static const struct can_speed_info can_speed_table[] = { + [CAN_SPEED_125] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 125000UL - 1) + )}, + [CAN_SPEED_250] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 250000UL - 1) + )}, + [CAN_SPEED_500] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 500000UL - 1) + )}, + [CAN_SPEED_1000] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 1000000UL - 1) + )} +}; + +CAN_STATUS status; +CanMsg can_rx_queue[CAN_RX_QUEUE_SIZE]; + +uint8 can_rx_head; +uint8 can_rx_tail; +uint8 can_rx_count; +uint8 can_rx_lost; +uint8 can_active = 0; + +/** + * @brief Return last operation status + */ +CAN_STATUS can_status(void) +{ + return status; +} + +/** + * @brief Enter initialization mode + */ +CAN_STATUS can_init_enter(CAN_Port* CANx) +{ + volatile uint32 wait_ack = 0 ; + + status = CAN_OK; + if ((CANx->MSR & CAN_MSR_INAK) == 0) // Check for initialization mode already set + { + CANx->MCR |= CAN_MCR_INRQ; // Request initialisation + + wait_ack = 0; // Wait the acknowledge + while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) == 0)) + wait_ack++; + if ((CANx->MSR & CAN_MSR_INAK) == 0) + status = CAN_INIT_E_FAILED; // Timeout + } + return status; +} + +/** + * @brief Leave initialization mode + */ +CAN_STATUS can_init_leave(CAN_Port* CANx) +{ + volatile uint32 wait_ack = 0 ; + + status = CAN_OK; + if ((CANx->MSR & CAN_MSR_INAK) != 0) // Check for initialization mode already reset + { + CANx->MCR &= ~CAN_MCR_INRQ; // Clear Request initialization + + wait_ack = 0; // Wait the acknowledge + while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) != 0)) + wait_ack++; + if ((CANx->MSR & CAN_MSR_INAK) != 0) + status = CAN_INIT_L_FAILED; + } + return status; +} + +/** + * @brief Deinitializes the CAN peripheral registers to their default reset values. + */ +CAN_STATUS can_deinit(CAN_Port* CANx) +{ + if (CANx == CAN1_BASE) + { + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // Disable interrupts + nvic_irq_disable(NVIC_USB_HP_CAN_TX); + rcc_reset_dev(RCC_CAN); + rcc_clk_disable(RCC_CAN); + can_active = 0; + } + return (status = CAN_OK); +} + +/** + * @brief Initialize CAN registers + */ +/* + * Bits in control parameter: + * CAN_MCR_TTCM time triggered communication mode + * CAN_MCR_ABOM automatic bus-off management + * CAN_MCR_AWUM automatic wake-up mode + * CAN_MCR_NART no automatic retransmission + * CAN_MCR_RFLM receive FIFO locked mode + * CAN_MCR_TXFP transmit FIFO priority + */ +CAN_STATUS can_init(CAN_Port* CANx, uint32 control, uint8 speed) +{ + status = CAN_INIT_FAILED; // default result status + // initialize receive message queue + can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; + + rcc_reset_dev(RCC_USB); //! X893 + rcc_clk_disable(RCC_USB); //! X893 +// line_dtr_rts = 0; //! X893 + rcc_clk_enable(RCC_AFIO); // enable clocks for AFIO + rcc_clk_enable(RCC_CAN); // and CAN + rcc_reset_dev(RCC_CAN); // reset CAN interface + + can_active = 1; // set CAN active flag (for interrupt handler + + CANx->MCR &= ~CAN_MCR_SLEEP; // reset CAN sleep mode (default after reset) + + if (can_init_enter(CANx) != CAN_OK) // enter CAN initialization mode + return status; // error, so return + + CANx->MCR &= ~CAN_CONTROL_MASK; // set mode bits + CANx->MCR |= (control & CAN_CONTROL_MASK); + + CANx->BTR &= ~CAN_TIMING_MASK; // Set the bit timing register + CANx->BTR |= (can_speed_table[speed].btr & CAN_TIMING_MASK); + + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // Enable interrupts + + nvic_irq_enable(NVIC_USB_HP_CAN_TX); + + CANx->IER = (CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | CAN_IER_TMEIE); + + if (can_init_leave(CANx) == CAN_OK) + { + while (!(CANx->TSR & CAN_TSR_TME0)); // Transmit mailbox 0 is empty + while (!(CANx->TSR & CAN_TSR_TME1)); // Transmit mailbox 0 is empty + while (!(CANx->TSR & CAN_TSR_TME2)); // Transmit mailbox 0 is empty + } + return status; +} + +/** + * @brief Set timing calues (CAN_BTR) + */ +CAN_STATUS can_set_timing(CAN_Port* CANx, uint32 timing) +{ + if (can_init_enter(CANx) == CAN_OK) + { + CANx->BTR = ((CANx->BTR & ~CAN_TIMING_MASK) | (timing & CAN_TIMING_MASK)); + can_init_leave(CANx); + } + return status; +} + +/** + * @brief Set CAN mode + * @param CANx pointer to CAN port + * @param mode CAN mode + */ +CAN_STATUS can_set_mode(CAN_Port* CANx, uint32 mode) +{ + if (can_init_enter(CANx) == CAN_OK) + { + CANx->BTR &= ~CAN_MODE_MASK; + CANx->BTR |= (mode & CAN_MODE_MASK); + can_init_leave(CANx); + } + return status; +} + +/** + * @brief Set CAN to GPIO mapping + */ +CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode) +{ + rcc_clk_enable(RCC_AFIO); + + status = CAN_INIT_FAILED; + if( CANx == CAN1_BASE) + { + switch(map_mode) + { + case CAN_GPIO_PB8_PB9: + rcc_clk_enable(RCC_GPIOB); + afio_remap(AFIO_MAPR_CAN_REMAP_PB8_PB9); + gpio_set_mode(GPIOB, 8, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOB, 9, GPIO_AF_OUTPUT_PP); + break; +#if NR_GPIO_PORTS >= 4 + case CAN_GPIO_PD0_PD1: + rcc_clk_enable(RCC_GPIOD); + afio_remap(AFIO_MAPR_CAN_REMAP_PD0_PD1); + gpio_set_mode(GPIOD, 0, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); + break; +#endif + default: + return status; + } + status = CAN_OK; + } + return status; +} + +CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2) +{ + uint32 mask = ((uint32)0x00000001) << filter_idx; + + CANx->FMR |= CAN_FMR_FINIT; // Initialization mode for the filter + CANx->FA1R &= ~mask; // Deactivation filter + + + if (scale == CAN_FILTER_32BIT) + CANx->FS1R |= mask; + else + CANx->FS1R &= ~mask; + + CANx->sFilterRegister[filter_idx].FR1 = fr1; + CANx->sFilterRegister[filter_idx].FR2 = fr2; + + if (mode == CAN_FILTER_MASK) + CANx->FM1R &= ~mask; + else + CANx->FM1R |= mask; + + if (fifo == CAN_FIFO0) + CANx->FFA1R &= ~mask; + else + CANx->FFA1R |= mask; + + CANx->FA1R |= mask; + CANx->FMR &= ~CAN_FMR_FINIT; + return CAN_OK; +} + +/** + * @brief Initiates the transmission of a message. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param msg: pointer to a structure which contains CAN Id, CAN DLC and CAN datas. + * @retval : The number of the mailbox that is used for transmission or CAN_NO_MB if there is no empty mailbox. + */ +CAN_TX_MBX can_transmit(CAN_Port* CANx, CanMsg* msg) +{ + CAN_TX_MBX mbx; + uint32 data; + + /* Select one empty transmit mailbox */ + if (CANx->TSR & CAN_TSR_TME0) + mbx = CAN_TX_MBX0; + else if (CANx->TSR & CAN_TSR_TME1) + mbx = CAN_TX_MBX1; + else if (CANx->TSR & CAN_TSR_TME2) + mbx = CAN_TX_MBX2; + else + { + status = CAN_NO_MB; + return CAN_TX_NO_MBX; + } + + /* Set up the Id */ + if (msg->IDE == CAN_ID_STD) + data = (msg->ID << 21); + else + data = (msg->ID << 3) | CAN_ID_EXT; + + data |= ((uint32)msg->RTR); + + /* Set up the DLC */ + CANx->sTxMailBox[mbx].TDTR = (uint32)(msg->DLC & 0x0F); + + /* Set up the data field */ + CANx->sTxMailBox[mbx].TDLR = ( + ((uint32)msg->Data[3] << 24) | + ((uint32)msg->Data[2] << 16) | + ((uint32)msg->Data[1] << 8) | + ((uint32)msg->Data[0]) + ); + CANx->sTxMailBox[mbx].TDHR = ( + ((uint32)msg->Data[7] << 24) | + ((uint32)msg->Data[6] << 16) | + ((uint32)msg->Data[5] << 8) | + ((uint32)msg->Data[4]) + ); + /* Request transmission */ + CANx->sTxMailBox[mbx].TIR = (data | CAN_TMIDxR_TXRQ); + status = CAN_OK; + + return mbx; +} + +/** + * Checks the transmission of a message. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param mbx: the number of the mailbox that is used for transmission. + * @retval : CAN_TX_OK if the CAN driver transmits the message, CAN_TX_FAILED in an other case. + */ +CAN_STATUS can_tx_status(CAN_Port* CANx, CAN_TX_MBX mbx) +{ + /* RQCP, TXOK and TME bits */ + uint8 state = 0; + + switch (mbx) + { + case CAN_TX_MBX0: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP0) << 2); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK0) >> 0); + state |= (uint8)((CANx->TSR & CAN_TSR_TME0) >> 26); + break; + case CAN_TX_MBX1: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP1) >> 6); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK1) >> 8); + state |= (uint8)((CANx->TSR & CAN_TSR_TME1) >> 27); + break; + case CAN_TX_MBX2: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP2) >> 14); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK2) >> 16); + state |= (uint8)((CANx->TSR & CAN_TSR_TME2) >> 28); + break; + default: + status = CAN_TX_FAILED; + return status; + } + + // state = RQCP TXOK TME + switch (state) + { + /* transmit pending */ + case 0x0: + status = CAN_TX_PENDING; + break; + /* transmit failed */ + case 0x5: + status = CAN_TX_FAILED; + break; + /* transmit succedeed */ + case 0x7: + status = CAN_OK; + break; + default: + status = CAN_TX_FAILED; + break; + } + return status; +} + +/** + * @brief Cancels a transmit request. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param mbx: Mailbox number. + * @retval : None. + */ +void can_cancel(CAN_Port* CANx, uint8 mbx) +{ + /* abort transmission */ + switch (mbx) + { + case 0: + CANx->TSR |= CAN_TSR_ABRQ0; + break; + case 1: + CANx->TSR |= CAN_TSR_ABRQ1; + break; + case 2: + CANx->TSR |= CAN_TSR_ABRQ2; + break; + default: + break; + } +} + +void can_rx_queue_clear(void) +{ + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); + can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); +} + +uint8 can_rx_available(void) +{ + return can_rx_count; +} + +CanMsg* can_rx_queue_get(void) +{ + if (can_rx_count == 0) + return NULL; + return &(can_rx_queue[can_rx_tail]); +} + +void can_rx_queue_free(void) +{ + if (can_rx_count > 0) + { + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // JMD problème d'atomicité + can_rx_tail = (can_rx_tail == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_tail + 1); + --can_rx_count; + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // fin JMD problème d'atomicité + } +} + +CanMsg* can_read(CAN_Port* CANx, CAN_FIFO fifo, CanMsg* msg) +{ + uint32 data = CANx->sFIFOMailBox[fifo].RIR; + + /* Get the Id */ + if (data & CAN_ID_EXT) + { + msg->ID = 0x1FFFFFFF & (data >> 3); + msg->IDE = (uint8)CAN_ID_EXT; + } + else + { + msg->ID = 0x000007FF & (data >> 21); + msg->IDE = (uint8)CAN_ID_STD; + } + + msg->RTR = (uint8)(CAN_RTR_REMOTE & data); + msg->DLC = (uint8)(0x0F & CANx->sFIFOMailBox[fifo].RDTR); + msg->FMI = (uint8)(0xFF & (CANx->sFIFOMailBox[fifo].RDTR >> 8)); + + /* Get the data field */ + data = CANx->sFIFOMailBox[fifo].RDLR; + uint8* p = msg->Data; + *p++ = (uint8)0xFF & data; + *p++ = (uint8)0xFF & (data >> 8); + *p++ = (uint8)0xFF & (data >> 16); + *p++ = (uint8)0xFF & (data >> 24); + + data = CANx->sFIFOMailBox[fifo].RDHR; + *p++ = (uint8)0xFF & data; + *p++ = (uint8)0xFF & (data >> 8); + *p++ = (uint8)0xFF & (data >> 16); + *p++ = (uint8)0xFF & (data >> 24); + + return msg; +} + +void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo) +{ + if (fifo == CAN_FIFO0) + CANx->RF0R |= (CAN_RF0R_RFOM0); // Release FIFO0 + else + CANx->RF1R |= (CAN_RF1R_RFOM1); // Release FIFO1 +} + +void can_rx_read(CAN_Port* CANx, CAN_FIFO fifo) +{ + if (can_rx_count < CAN_RX_QUEUE_SIZE) // read the message + { + CanMsg* msg = &can_rx_queue[can_rx_head]; + can_read(CANx, fifo, msg); + can_rx_head = (can_rx_head == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_head + 1); + can_rx_count++; + } + else + can_rx_lost = 1; // no place in queue, ignore package + + can_rx_release(CANx, fifo); +} + +uint8 CAN_RX0_IRQ_Handler(void) +{ + if (can_active) + { + while ((CAN1_BASE->RF0R & CAN_RF0R_FMP0) != 0) + can_rx_read(CAN1_BASE, CAN_FIFO0); // message pending FIFO0 + while ((CAN1_BASE->RF1R & CAN_RF1R_FMP1) != 0) + can_rx_read(CAN1_BASE, CAN_FIFO1); // message pending FIFO1 + } + return can_active; // return CAN active flag to USB handler +} + +void USB_HP_CAN_TX_IRQHandler (void) +{ + if (can_active) + { + if (CAN1_BASE->TSR & CAN_TSR_RQCP0) + CAN1_BASE->TSR |= CAN_TSR_RQCP0; // reset request complete mbx 0 + if (CAN1_BASE->TSR & CAN_TSR_RQCP1) + CAN1_BASE->TSR |= CAN_TSR_RQCP1; // reset request complete mbx 1 + if (CAN1_BASE->TSR & CAN_TSR_RQCP2) + CAN1_BASE->TSR |= CAN_TSR_RQCP2; // reset request complete mbx 2 + } +} diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.h b/STM32F1/libraries/HardwareCAN/src/utility/can.h new file mode 100644 index 000000000..576ac36fe --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.h @@ -0,0 +1,322 @@ +#ifndef _CAN_H_ +#define _CAN_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +//#include "libmaple_types.h" +#include +#include +#include "libmaple/nvic.h" +#include +//#include "types.h" +#include "libmaple/usb.h" + +#ifndef CAN_RX_QUEUE_SIZE + #define CAN_RX_QUEUE_SIZE 16 +#endif + +/* peripheral addresses */ +#define CAN1_BASE ((CAN_Port*)0x40006400) +#define CAN2_BASE ((CAN_Port*)0x40006800) + + +/* CAN Master Control Register bits */ +#define CAN_MCR_INRQ ((uint32)0x00000001) /* Initialization request */ +#define CAN_MCR_SLEEP ((uint32)0x00000002) /* Sleep mode request */ +#define CAN_MCR_TXFP ((uint32)0x00000004) /* Transmit FIFO priority */ +#define CAN_MCR_RFLM ((uint32)0x00000008) /* Receive FIFO locked mode */ +#define CAN_MCR_NART ((uint32)0x00000010) /* No automatic retransmission */ +#define CAN_MCR_AWUM ((uint32)0x00000020) /* Automatic wake up mode */ +#define CAN_MCR_ABOM ((uint32)0x00000040) /* Automatic bus-off management */ +#define CAN_MCR_TTCM ((uint32)0x00000080) /* Time triggered communication mode */ +#define CAN_MCR_RESET ((uint32)0x00008000) /* bxCAN software master reset */ +#define CAN_MCR_DBF ((uint32)0x00010000) /* Debug freeze */ + +/* CAN Master Status Register bits */ +#define CAN_MSR_INAK ((uint32)0x00000001) /* Initialization acknowledge */ +#define CAN_MSR_SLAK ((uint32)0x00000002) /* Sleep acknowledge */ +#define CAN_MSR_ERRI ((uint32)0x00000004) /* Error interrupt */ +#define CAN_MSR_WKUI ((uint32)0x00000008) /* Wake-up interrupt */ +#define CAN_MSR_SLAKI ((uint32)0x00000010) /* Sleep acknowledge interrupt */ +#define CAN_MSR_TXM ((uint32)0x00000100) /* Transmit mode */ +#define CAN_MSR_RXM ((uint32)0x00000200) /* Receive mode */ +#define CAN_MSR_SAMP ((uint32)0x00000400) /* Last sample point */ +#define CAN_MSR_RX ((uint32)0x00000800) /* CAN Rx signal */ + +/* CAN Transmit Status Register bits */ +#define CAN_TSR_RQCP0 ((uint32)0x00000001) /* Request completed mailbox0 */ +#define CAN_TSR_TXOK0 ((uint32)0x00000002) /* Transmission OK of mailbox0 */ +#define CAN_TSR_ALST0 ((uint32)0x00000004) /* Arbitration Lost for Mailbox0 */ +#define CAN_TSR_TERR0 ((uint32)0x00000008) /* Transmission Error of Mailbox0 */ +#define CAN_TSR_ABRQ0 ((uint32)0x00000080) /* Abort request for mailbox0 */ +#define CAN_TSR_RQCP1 ((uint32)0x00000100) /* Request completed mailbox1 */ +#define CAN_TSR_TXOK1 ((uint32)0x00000200) /* Transmission OK of mailbox1 */ +#define CAN_TSR_ALST1 ((uint32)0x00000400) /* Arbitration Lost for Mailbox1 */ +#define CAN_TSR_TERR1 ((uint32)0x00000800) /* Transmission Error of Mailbox1 */ +#define CAN_TSR_ABRQ1 ((uint32)0x00008000) /* Abort request for mailbox1 */ +#define CAN_TSR_RQCP2 ((uint32)0x00010000) /* Request completed mailbox2 */ +#define CAN_TSR_TXOK2 ((uint32)0x00020000) /* Transmission OK of mailbox2 */ +#define CAN_TSR_ALST2 ((uint32)0x00040000) /* Arbitration Lost for mailbox 2 */ +#define CAN_TSR_TERR2 ((uint32)0x00080000) /* Transmission Error of Mailbox 2 */ +#define CAN_TSR_ABRQ2 ((uint32)0x00800000) /* Abort request for mailbox2 */ +#define CAN_TSR_CODE ((uint32)0x03000000) /* Mailbox Code */ +#define CAN_TSR_TME ((uint32)0x1C000000) /* TME[2:0] bits */ +#define CAN_TSR_TME0 ((uint32)0x04000000) /* Transmit mailbox 0 empty */ +#define CAN_TSR_TME1 ((uint32)0x08000000) /* Transmit mailbox 1 empty */ +#define CAN_TSR_TME2 ((uint32)0x10000000) /* Transmit mailbox 2 empty */ +#define CAN_TSR_LOW ((uint32)0xE0000000) /* LOW[2:0] bits */ +#define CAN_TSR_LOW0 ((uint32)0x20000000) /* Lowest Priority Flag for Mailbox 0 */ +#define CAN_TSR_LOW1 ((uint32)0x40000000) /* Lowest Priority Flag for Mailbox 1 */ +#define CAN_TSR_LOW2 ((uint32)0x80000000) /* Lowest Priority Flag for Mailbox 2 */ + +/* CAN Receive FIFO 0 Register bits */ +#define CAN_RF0R_FMP0 ((uint32)0x00000003) /* FIFO 0 message pending */ +#define CAN_RF0R_FULL0 ((uint32)0x00000008) /* FIFO 0 full */ +#define CAN_RF0R_FOVR0 ((uint32)0x00000010) /* FIFO 0 overrun */ +#define CAN_RF0R_RFOM0 ((uint32)0x00000020) /* Release FIFO 0 output mailbox */ + +/* CAN Receive FIFO 1 Register bits */ +#define CAN_RF1R_FMP1 ((uint32)0x00000003) /* FIFO 1 message pending */ +#define CAN_RF1R_FULL1 ((uint32)0x00000008) /* FIFO 1 full */ +#define CAN_RF1R_FOVR1 ((uint32)0x00000010) /* FIFO 1 overrun */ +#define CAN_RF1R_RFOM1 ((uint32)0x00000020) /* Release FIFO 1 output mailbox */ + +/* CAN Error Status Register bits */ +#define CAN_ESR_EWGF ((uint32)0x00000001) /* Error warning flag */ +#define CAN_ESR_EPVF ((uint32)0x00000002) /* Error passive flag */ +#define CAN_ESR_BOFF ((uint32)0x00000004) /* Bus-off flag */ + +/* CAN interrupt enable register (CAN_IER) */ +#define CAN_IER_TMEIE ((uint32)0x00000001) /* Transmit Mailbox Empty Interrupt Enable */ +#define CAN_IER_FMPIE0 ((uint32)0x00000002) /* FIFO Message Pending Interrupt Enable */ +#define CAN_IER_FFIE0 ((uint32)0x00000004) /* FIFO Full Interrupt Enable */ +#define CAN_IER_FOVIE0 ((uint32)0x00000008) /* FIFO Overrun Interrupt Enable */ +#define CAN_IER_FMPIE1 ((uint32)0x00000010) /* FIFO Message Pending Interrupt Enable */ +#define CAN_IER_FFIE1 ((uint32)0x00000020) /* FIFO Full Interrupt Enable */ +#define CAN_IER_FOVIE1 ((uint32)0x00000040) /* FIFO Overrun Interrupt Enable */ +#define CAN_IER_EWGIE ((uint32)0x00000100) /* Error Warning Interrupt Enable */ +#define CAN_IER_EPVIE ((uint32)0x00000200) /* Error Passive Interrupt Enable */ +#define CAN_IER_BOFIE ((uint32)0x00000400) /* Bus-Off Interrupt Enable */ +#define CAN_IER_LECIE ((uint32)0x00000800) /* Last Error Code Interrupt Enable */ +#define CAN_IER_ERRIE ((uint32)0x00008000) /* Error Interrupt Enable */ +#define CAN_IER_WKUIE ((uint32)0x00010000) /* Wakeup Interrupt Enable */ +#define CAN_IER_SLKIE ((uint32)0x00020000) /* Sleep Interrupt Enable */ + +/* CAN error status register (CAN_ESR) */ +#define CAN_ESR_EWGF ((uint32)0x00000001) /* Error Warning Flag */ +#define CAN_ESR_EPVF ((uint32)0x00000002) /* Error Passive Flag */ +#define CAN_ESR_BOFF ((uint32)0x00000004) /* Bus-Off Flag */ + +#define CAN_ESR_LEC ((uint32)0x00000070) /* LEC[2:0] bits (Last Error Code) */ +#define CAN_ESR_LEC_0 ((uint32)0x00000010) /* Bit 0 */ +#define CAN_ESR_LEC_1 ((uint32)0x00000020) /* Bit 1 */ +#define CAN_ESR_LEC_2 ((uint32)0x00000040) /* Bit 2 */ + +#define CAN_ESR_TEC ((uint32)0x00FF0000) /* Least significant byte of the 9-bit Transmit Error Counter */ +#define CAN_ESR_REC ((uint32)0xFF000000) /* Receive Error Counter */ + +/* CAN bit timing register (CAN_BTR) */ +#define CAN_BTR_SJW_POS 24 +#define CAN_BTR_TS2_POS 20 +#define CAN_BTR_TS1_POS 16 + +#define CAN_BTR_BRP ((uint32)0x000003FF) /* Baud Rate Prescaler */ +#define CAN_BTR_TS1 ((uint32)0x000F0000) /* Time Segment 1 */ +#define CAN_BTR_TS2 ((uint32)0x00700000) /* Time Segment 2 */ +#define CAN_BTR_SJW ((uint32)0x03000000) /* Resynchronization Jump Width */ +#define CAN_BTR_LBKM ((uint32)0x40000000) /* Loop Back Mode (Debug) */ +#define CAN_BTR_SILM ((uint32)0x80000000) /* Silent Mode */ + + +/* CAN Mailbox Transmit Request */ +#define CAN_TMIDxR_TXRQ ((uint32)0x00000001) /* Transmit mailbox request */ + +/* CAN Filter Master Register bits */ +#define CAN_FMR_FINIT ((uint32)0x00000001) /* Filter init mode */ + + +typedef enum CAN_GPIO_MAP { + CAN_GPIO_PB8_PB9, /* RX to PB8, TX to PB9 */ + CAN_GPIO_PD0_PD1 /* RX to PD0, TX to PD1 */ +} CAN_GPIO_MAP; + +typedef enum CAN_STATUS +{ + CAN_OK = 0, + CAN_INIT_FAILED, + CAN_INIT_E_FAILED, + CAN_INIT_L_FAILED, + CAN_TX_FAILED, + CAN_TX_PENDING, + CAN_NO_MB, + CAN_FILTER_FULL +} CAN_STATUS; + +typedef enum CAN_TX_MBX +{ + CAN_TX_MBX0 = 0, + CAN_TX_MBX1 = 1, + CAN_TX_MBX2 = 2, + CAN_TX_NO_MBX = CAN_NO_MB +} CAN_TX_MBX; + +#define CAN_MODE_NORMAL ((uint32)0x0) /* normal mode */ +#define CAN_MODE_LOOPBACK (CAN_BTR_LBKM) /* loopback mode */ +#define CAN_MODE_SILENT (CAN_BTR_SILM) /* silent mode */ +#define CAN_MODE_SILENT_LOOPBACK (CAN_BTR_LBKM | CAN_BTR_SILM) /* loopback combined with silent mode */ + +enum CAN_SPEED { + CAN_SPEED_125, + CAN_SPEED_250, + CAN_SPEED_500, + CAN_SPEED_1000, +}; + +/** + * CAN_identifier_type + */ +#define CAN_ID_STD ((uint32)0x00) /* Standard Id */ +#define CAN_ID_EXT ((uint32)0x04) /* Extended Id */ + +/** + * CAN_remote_transmission_request + */ +#define CAN_RTR_DATA ((uint32)0x00) /* Data frame */ +#define CAN_RTR_REMOTE ((uint32)0x02) /* Remote frame */ + +/** + * CAN_receive_FIFO_number_constants + */ +typedef enum { + CAN_FIFO0 = 0, + CAN_FIFO1 = 1 +} CAN_FIFO; + +typedef enum { + CAN_FILTER_32BIT = 0, + CAN_FILTER_16BIT = 1 +} CAN_FILTER_SCALE; + +typedef enum { + CAN_FILTER_MASK = 0, + CAN_FILTER_LIST = 1 +} CAN_FILTER_MODE; +/** + * @brief Controller Area Network TxMailBox + */ +typedef struct +{ + volatile uint32 TIR; + volatile uint32 TDTR; + volatile uint32 TDLR; + volatile uint32 TDHR; +} CAN_TxMailBox_Port; + +/** + * @brief Controller Area Network FIFOMailBox + */ +typedef struct +{ + volatile uint32 RIR; + volatile uint32 RDTR; + volatile uint32 RDLR; + volatile uint32 RDHR; +} CAN_FIFOMailBox_Port; + +/** + * @brief Controller Area Network FilterRegister + */ +typedef struct +{ + volatile uint32 FR1; + volatile uint32 FR2; +} CAN_FilterRegister_Port; + +typedef struct { + volatile uint32 MCR; // CAN master control register (CAN_MCR) + volatile uint32 MSR; // CAN master status register (CAN_MSR) + volatile uint32 TSR; // CAN transmit status register (CAN_TSR) + volatile uint32 RF0R; // CAN receive FIFO 0 register (CAN_RF0R) + volatile uint32 RF1R; // CAN receive FIFO 1 register (CAN_RF1R) + volatile uint32 IER; + volatile uint32 ESR; + volatile uint32 BTR; + uint32 RESERVED0[88]; + CAN_TxMailBox_Port sTxMailBox[3]; + CAN_FIFOMailBox_Port sFIFOMailBox[2]; + uint32 RESERVED1[12]; + volatile uint32 FMR; + volatile uint32 FM1R; + uint32 RESERVED2; + volatile uint32 FS1R; + uint32 RESERVED3; + volatile uint32 FFA1R; + uint32 RESERVED4; + volatile uint32 FA1R; + uint32 RESERVED5[8]; + CAN_FilterRegister_Port sFilterRegister[14]; +} CAN_Port; + +/** + * @brief CAN Tx message structure definition + */ +typedef struct +{ + uint32 ID; // CAN ID + uint8 IDE; // CAN_ID_STD for standard and CAN_ID_EXT for extended + uint8 RTR; + uint8 DLC; + uint8 Data[8]; + uint8 FMI; +} CanMsg; + +/* Functions */ +CAN_STATUS can_init_enter(CAN_Port* CANx); +CAN_STATUS can_init_leave(CAN_Port* CANx); +CAN_STATUS can_init(CAN_Port *CANx, uint32 mode, uint8 speed); +CAN_STATUS can_deinit(CAN_Port* CANx); +CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo_number, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2); +CAN_STATUS can_set_timing(CAN_Port* CANx, uint32 timing); +CAN_STATUS can_set_mode(CAN_Port* CANx, uint32 mode); +CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode); +CAN_STATUS can_status(void); +void can_cancel(CAN_Port* CANx, uint8 mbx); +void can_rx_queue_clear(void); +uint8 can_rx_available(void); +CanMsg* can_rx_queue_get(void); +CanMsg* can_read(CAN_Port* CANx, CAN_FIFO fifo, CanMsg* msg); +void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo); +void can_rx_queue_free(void); +CAN_TX_MBX can_transmit(CAN_Port* CANx, CanMsg* msg); +CAN_STATUS can_tx_status(CAN_Port* CANx, CAN_TX_MBX mbx); + +/** + * @brief Set pooling mode + */ +static inline void can_set_pool_mode(CAN_Port* CANx) +{ + CANx->IER &= ~(CAN_IER_FMPIE0 | CAN_IER_FMPIE1); +} + +/** + * @brief Set interrupt mode + */ +static inline void can_set_irq_mode(CAN_Port* CANx) +{ + CANx->IER |= (CAN_IER_FMPIE0 | CAN_IER_FMPIE1); +} + +static inline uint8 can_fifo_ready(CAN_Port* CANx, CAN_FIFO fifo) +{ + if (fifo == CAN_FIFO0) + return (uint8)(CANx->RF0R & CAN_RF0R_FMP0); + return (uint8)(CANx->RF1R & CAN_RF1R_FMP1); +} + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/rcc.h b/STM32F1/libraries/rcc.h new file mode 100644 index 000000000..aa9f8d3c9 --- /dev/null +++ b/STM32F1/libraries/rcc.h @@ -0,0 +1,641 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/include/series/rcc.h + * @brief STM32F1 reset and clock control (RCC) support. + */ + +#ifndef _LIBMAPLE_STM32F1_RCC_H_ +#define _LIBMAPLE_STM32F1_RCC_H_ + +#ifdef __cplusplus +extern "C"{ +#endif + +#include +#include + +/* + * Register map + */ + +/** STM32F1 RCC register map type */ +typedef struct rcc_reg_map { + __io uint32 CR; /**< Clock control register */ + __io uint32 CFGR; /**< Clock configuration register */ + __io uint32 CIR; /**< Clock interrupt register */ + __io uint32 APB2RSTR; /**< APB2 peripheral reset register */ + __io uint32 APB1RSTR; /**< APB1 peripheral reset register */ + __io uint32 AHBENR; /**< AHB peripheral clock enable register */ + __io uint32 APB2ENR; /**< APB2 peripheral clock enable register */ + __io uint32 APB1ENR; /**< APB1 peripheral clock enable register */ + __io uint32 BDCR; /**< Backup domain control register */ + __io uint32 CSR; /**< Control/status register */ +} rcc_reg_map; + +#define RCC_BASE ((struct rcc_reg_map*)0x40021000) + +/* + * Register bit definitions + */ + +/* Clock control register */ + +#define RCC_CR_PLLRDY_BIT 25 +#define RCC_CR_PLLON_BIT 24 +#define RCC_CR_CSSON_BIT 19 +#define RCC_CR_HSEBYP_BIT 18 +#define RCC_CR_HSERDY_BIT 17 +#define RCC_CR_HSEON_BIT 16 +#define RCC_CR_HSIRDY_BIT 1 +#define RCC_CR_HSION_BIT 0 + +#define RCC_CR_PLLRDY (1U << RCC_CR_PLLRDY_BIT) +#define RCC_CR_PLLON (1U << RCC_CR_PLLON_BIT) +#define RCC_CR_CSSON (1U << RCC_CR_CSSON_BIT) +#define RCC_CR_HSEBYP (1U << RCC_CR_HSEBYP_BIT) +#define RCC_CR_HSERDY (1U << RCC_CR_HSERDY_BIT) +#define RCC_CR_HSEON (1U << RCC_CR_HSEON_BIT) +#define RCC_CR_HSICAL (0xFF << 8) +#define RCC_CR_HSITRIM (0x1F << 3) +#define RCC_CR_HSIRDY (1U << RCC_CR_HSIRDY_BIT) +#define RCC_CR_HSION (1U << RCC_CR_HSION_BIT) + +/* Clock configuration register */ + +#define RCC_CFGR_USBPRE_BIT 22 +#define RCC_CFGR_PLLXTPRE_BIT 17 +#define RCC_CFGR_PLLSRC_BIT 16 + +#define RCC_CFGR_MCO (0x3 << 24) +#define RCC_CFGR_USBPRE (0x3 << RCC_CFGR_USBPRE_BIT) +#define RCC_CFGR_PLLMUL (0xF << 18) +#define RCC_CFGR_PLLXTPRE (1U << RCC_CFGR_PLLXTPRE_BIT) +#define RCC_CFGR_PLLSRC (1U << RCC_CFGR_PLLSRC_BIT) +#define RCC_CFGR_ADCPRE (0x3 << 14) +#define RCC_CFGR_PPRE2 (0x7 << 11) +#define RCC_CFGR_PPRE1 (0x7 << 8) +#define RCC_CFGR_HPRE (0xF << 4) +#define RCC_CFGR_SWS (0x3 << 2) +#define RCC_CFGR_SWS_PLL (0x2 << 2) +#define RCC_CFGR_SWS_HSE (0x1 << 2) +#define RCC_CFGR_SW 0x3 +#define RCC_CFGR_SW_PLL 0x2 +#define RCC_CFGR_SW_HSE 0x1 + +/* Clock interrupt register */ + +#define RCC_CIR_CSSC_BIT 23 +#define RCC_CIR_PLLRDYC_BIT 20 +#define RCC_CIR_HSERDYC_BIT 19 +#define RCC_CIR_HSIRDYC_BIT 18 +#define RCC_CIR_LSERDYC_BIT 17 +#define RCC_CIR_LSIRDYC_BIT 16 +#define RCC_CIR_PLLRDYIE_BIT 12 +#define RCC_CIR_HSERDYIE_BIT 11 +#define RCC_CIR_HSIRDYIE_BIT 10 +#define RCC_CIR_LSERDYIE_BIT 9 +#define RCC_CIR_LSIRDYIE_BIT 8 +#define RCC_CIR_CSSF_BIT 7 +#define RCC_CIR_PLLRDYF_BIT 4 +#define RCC_CIR_HSERDYF_BIT 3 +#define RCC_CIR_HSIRDYF_BIT 2 +#define RCC_CIR_LSERDYF_BIT 1 +#define RCC_CIR_LSIRDYF_BIT 0 + +#define RCC_CIR_CSSC (1U << RCC_CIR_CSSC_BIT) +#define RCC_CIR_PLLRDYC (1U << RCC_CIR_PLLRDYC_BIT) +#define RCC_CIR_HSERDYC (1U << RCC_CIR_HSERDYC_BIT) +#define RCC_CIR_HSIRDYC (1U << RCC_CIR_HSIRDYC_BIT) +#define RCC_CIR_LSERDYC (1U << RCC_CIR_LSERDYC_BIT) +#define RCC_CIR_LSIRDYC (1U << RCC_CIR_LSIRDYC_BIT) +#define RCC_CIR_PLLRDYIE (1U << RCC_CIR_PLLRDYIE_BIT) +#define RCC_CIR_HSERDYIE (1U << RCC_CIR_HSERDYIE_BIT) +#define RCC_CIR_HSIRDYIE (1U << RCC_CIR_HSIRDYIE_BIT) +#define RCC_CIR_LSERDYIE (1U << RCC_CIR_LSERDYIE_BIT) +#define RCC_CIR_LSIRDYIE (1U << RCC_CIR_LSIRDYIE_BIT) +#define RCC_CIR_CSSF (1U << RCC_CIR_CSSF_BIT) +#define RCC_CIR_PLLRDYF (1U << RCC_CIR_PLLRDYF_BIT) +#define RCC_CIR_HSERDYF (1U << RCC_CIR_HSERDYF_BIT) +#define RCC_CIR_HSIRDYF (1U << RCC_CIR_HSIRDYF_BIT) +#define RCC_CIR_LSERDYF (1U << RCC_CIR_LSERDYF_BIT) +#define RCC_CIR_LSIRDYF (1U << RCC_CIR_LSIRDYF_BIT) + +/* APB2 peripheral reset register */ + +#define RCC_APB2RSTR_TIM11RST_BIT 21 +#define RCC_APB2RSTR_TIM10RST_BIT 20 +#define RCC_APB2RSTR_TIM9RST_BIT 19 +#define RCC_APB2RSTR_ADC3RST_BIT 15 +#define RCC_APB2RSTR_USART1RST_BIT 14 +#define RCC_APB2RSTR_TIM8RST_BIT 13 +#define RCC_APB2RSTR_SPI1RST_BIT 12 +#define RCC_APB2RSTR_TIM1RST_BIT 11 +#define RCC_APB2RSTR_ADC2RST_BIT 10 +#define RCC_APB2RSTR_ADC1RST_BIT 9 +#define RCC_APB2RSTR_IOPGRST_BIT 8 +#define RCC_APB2RSTR_IOPFRST_BIT 7 +#define RCC_APB2RSTR_IOPERST_BIT 6 +#define RCC_APB2RSTR_IOPDRST_BIT 5 +#define RCC_APB2RSTR_IOPCRST_BIT 4 +#define RCC_APB2RSTR_IOPBRST_BIT 3 +#define RCC_APB2RSTR_IOPARST_BIT 2 +#define RCC_APB2RSTR_AFIORST_BIT 0 + +#define RCC_APB2RSTR_TIM11RST (1U << RCC_APB2RSTR_TIM11RST_BIT) +#define RCC_APB2RSTR_TIM10RST (1U << RCC_APB2RSTR_TIM10RST_BIT) +#define RCC_APB2RSTR_TIM9RST (1U << RCC_APB2RSTR_TIM9RST_BIT) +#define RCC_APB2RSTR_ADC3RST (1U << RCC_APB2RSTR_ADC3RST_BIT) +#define RCC_APB2RSTR_USART1RST (1U << RCC_APB2RSTR_USART1RST_BIT) +#define RCC_APB2RSTR_TIM8RST (1U << RCC_APB2RSTR_TIM8RST_BIT) +#define RCC_APB2RSTR_SPI1RST (1U << RCC_APB2RSTR_SPI1RST_BIT) +#define RCC_APB2RSTR_TIM1RST (1U << RCC_APB2RSTR_TIM1RST_BIT) +#define RCC_APB2RSTR_ADC2RST (1U << RCC_APB2RSTR_ADC2RST_BIT) +#define RCC_APB2RSTR_ADC1RST (1U << RCC_APB2RSTR_ADC1RST_BIT) +#define RCC_APB2RSTR_IOPGRST (1U << RCC_APB2RSTR_IOPGRST_BIT) +#define RCC_APB2RSTR_IOPFRST (1U << RCC_APB2RSTR_IOPFRST_BIT) +#define RCC_APB2RSTR_IOPERST (1U << RCC_APB2RSTR_IOPERST_BIT) +#define RCC_APB2RSTR_IOPDRST (1U << RCC_APB2RSTR_IOPDRST_BIT) +#define RCC_APB2RSTR_IOPCRST (1U << RCC_APB2RSTR_IOPCRST_BIT) +#define RCC_APB2RSTR_IOPBRST (1U << RCC_APB2RSTR_IOPBRST_BIT) +#define RCC_APB2RSTR_IOPARST (1U << RCC_APB2RSTR_IOPARST_BIT) +#define RCC_APB2RSTR_AFIORST (1U << RCC_APB2RSTR_AFIORST_BIT) + +/* APB1 peripheral reset register */ + +#define RCC_APB1RSTR_DACRST_BIT 29 +#define RCC_APB1RSTR_PWRRST_BIT 28 +#define RCC_APB1RSTR_BKPRST_BIT 27 +#define RCC_APB1RSTR_CANRST_BIT 25 +#define RCC_APB1RSTR_USBRST_BIT 23 +#define RCC_APB1RSTR_I2C2RST_BIT 22 +#define RCC_APB1RSTR_I2C1RST_BIT 21 +#define RCC_APB1RSTR_UART5RST_BIT 20 +#define RCC_APB1RSTR_UART4RST_BIT 19 +#define RCC_APB1RSTR_USART3RST_BIT 18 +#define RCC_APB1RSTR_USART2RST_BIT 17 +#define RCC_APB1RSTR_SPI3RST_BIT 15 +#define RCC_APB1RSTR_SPI2RST_BIT 14 +#define RCC_APB1RSTR_WWDRST_BIT 11 +#define RCC_APB1RSTR_TIM14RST_BIT 8 +#define RCC_APB1RSTR_TIM13RST_BIT 7 +#define RCC_APB1RSTR_TIM12RST_BIT 6 +#define RCC_APB1RSTR_TIM7RST_BIT 5 +#define RCC_APB1RSTR_TIM6RST_BIT 4 +#define RCC_APB1RSTR_TIM5RST_BIT 3 +#define RCC_APB1RSTR_TIM4RST_BIT 2 +#define RCC_APB1RSTR_TIM3RST_BIT 1 +#define RCC_APB1RSTR_TIM2RST_BIT 0 + +#define RCC_APB1RSTR_DACRST (1U << RCC_APB1RSTR_DACRST_BIT) +#define RCC_APB1RSTR_PWRRST (1U << RCC_APB1RSTR_PWRRST_BIT) +#define RCC_APB1RSTR_BKPRST (1U << RCC_APB1RSTR_BKPRST_BIT) +#define RCC_APB1RSTR_CANRST (1U << RCC_APB1RSTR_CANRST_BIT) +#define RCC_APB1RSTR_USBRST (1U << RCC_APB1RSTR_USBRST_BIT) +#define RCC_APB1RSTR_I2C2RST (1U << RCC_APB1RSTR_I2C2RST_BIT) +#define RCC_APB1RSTR_I2C1RST (1U << RCC_APB1RSTR_I2C1RST_BIT) +#define RCC_APB1RSTR_UART5RST (1U << RCC_APB1RSTR_UART5RST_BIT) +#define RCC_APB1RSTR_UART4RST (1U << RCC_APB1RSTR_UART4RST_BIT) +#define RCC_APB1RSTR_USART3RST (1U << RCC_APB1RSTR_USART3RST_BIT) +#define RCC_APB1RSTR_USART2RST (1U << RCC_APB1RSTR_USART2RST_BIT) +#define RCC_APB1RSTR_SPI3RST (1U << RCC_APB1RSTR_SPI3RST_BIT) +#define RCC_APB1RSTR_SPI2RST (1U << RCC_APB1RSTR_SPI2RST_BIT) +#define RCC_APB1RSTR_WWDRST (1U << RCC_APB1RSTR_WWDRST_BIT) +#define RCC_APB1RSTR_TIM14RST (1U << RCC_APB1RSTR_TIM14RST_BIT) +#define RCC_APB1RSTR_TIM13RST (1U << RCC_APB1RSTR_TIM13RST_BIT) +#define RCC_APB1RSTR_TIM12RST (1U << RCC_APB1RSTR_TIM12RST_BIT) +#define RCC_APB1RSTR_TIM7RST (1U << RCC_APB1RSTR_TIM7RST_BIT) +#define RCC_APB1RSTR_TIM6RST (1U << RCC_APB1RSTR_TIM6RST_BIT) +#define RCC_APB1RSTR_TIM5RST (1U << RCC_APB1RSTR_TIM5RST_BIT) +#define RCC_APB1RSTR_TIM4RST (1U << RCC_APB1RSTR_TIM4RST_BIT) +#define RCC_APB1RSTR_TIM3RST (1U << RCC_APB1RSTR_TIM3RST_BIT) +#define RCC_APB1RSTR_TIM2RST (1U << RCC_APB1RSTR_TIM2RST_BIT) + +/* AHB peripheral clock enable register */ + +#define RCC_AHBENR_SDIOEN_BIT 10 +#define RCC_AHBENR_FSMCEN_BIT 8 +#define RCC_AHBENR_CRCEN_BIT 7 +#define RCC_AHBENR_FLITFEN_BIT 4 +#define RCC_AHBENR_SRAMEN_BIT 2 +#define RCC_AHBENR_DMA2EN_BIT 1 +#define RCC_AHBENR_DMA1EN_BIT 0 + +#define RCC_AHBENR_SDIOEN (1U << RCC_AHBENR_SDIOEN_BIT) +#define RCC_AHBENR_FSMCEN (1U << RCC_AHBENR_FSMCEN_BIT) +#define RCC_AHBENR_CRCEN (1U << RCC_AHBENR_CRCEN_BIT) +#define RCC_AHBENR_FLITFEN (1U << RCC_AHBENR_FLITFEN_BIT) +#define RCC_AHBENR_SRAMEN (1U << RCC_AHBENR_SRAMEN_BIT) +#define RCC_AHBENR_DMA2EN (1U << RCC_AHBENR_DMA2EN_BIT) +#define RCC_AHBENR_DMA1EN (1U << RCC_AHBENR_DMA1EN_BIT) + +/* APB2 peripheral clock enable register */ + +#define RCC_APB2ENR_TIM11EN_BIT 21 +#define RCC_APB2ENR_TIM10EN_BIT 20 +#define RCC_APB2ENR_TIM9EN_BIT 19 +#define RCC_APB2ENR_ADC3EN_BIT 15 +#define RCC_APB2ENR_USART1EN_BIT 14 +#define RCC_APB2ENR_TIM8EN_BIT 13 +#define RCC_APB2ENR_SPI1EN_BIT 12 +#define RCC_APB2ENR_TIM1EN_BIT 11 +#define RCC_APB2ENR_ADC2EN_BIT 10 +#define RCC_APB2ENR_ADC1EN_BIT 9 +#define RCC_APB2ENR_IOPGEN_BIT 8 +#define RCC_APB2ENR_IOPFEN_BIT 7 +#define RCC_APB2ENR_IOPEEN_BIT 6 +#define RCC_APB2ENR_IOPDEN_BIT 5 +#define RCC_APB2ENR_IOPCEN_BIT 4 +#define RCC_APB2ENR_IOPBEN_BIT 3 +#define RCC_APB2ENR_IOPAEN_BIT 2 +#define RCC_APB2ENR_AFIOEN_BIT 0 + +#define RCC_APB2ENR_TIM11EN (1U << RCC_APB2ENR_TIM11EN_BIT) +#define RCC_APB2ENR_TIM10EN (1U << RCC_APB2ENR_TIM10EN_BIT) +#define RCC_APB2ENR_TIM9EN (1U << RCC_APB2ENR_TIM9EN_BIT) +#define RCC_APB2ENR_ADC3EN (1U << RCC_APB2ENR_ADC3EN_BIT) +#define RCC_APB2ENR_USART1EN (1U << RCC_APB2ENR_USART1EN_BIT) +#define RCC_APB2ENR_TIM8EN (1U << RCC_APB2ENR_TIM8EN_BIT) +#define RCC_APB2ENR_SPI1EN (1U << RCC_APB2ENR_SPI1EN_BIT) +#define RCC_APB2ENR_TIM1EN (1U << RCC_APB2ENR_TIM1EN_BIT) +#define RCC_APB2ENR_ADC2EN (1U << RCC_APB2ENR_ADC2EN_BIT) +#define RCC_APB2ENR_ADC1EN (1U << RCC_APB2ENR_ADC1EN_BIT) +#define RCC_APB2ENR_IOPGEN (1U << RCC_APB2ENR_IOPGEN_BIT) +#define RCC_APB2ENR_IOPFEN (1U << RCC_APB2ENR_IOPFEN_BIT) +#define RCC_APB2ENR_IOPEEN (1U << RCC_APB2ENR_IOPEEN_BIT) +#define RCC_APB2ENR_IOPDEN (1U << RCC_APB2ENR_IOPDEN_BIT) +#define RCC_APB2ENR_IOPCEN (1U << RCC_APB2ENR_IOPCEN_BIT) +#define RCC_APB2ENR_IOPBEN (1U << RCC_APB2ENR_IOPBEN_BIT) +#define RCC_APB2ENR_IOPAEN (1U << RCC_APB2ENR_IOPAEN_BIT) +#define RCC_APB2ENR_AFIOEN (1U << RCC_APB2ENR_AFIOEN_BIT) + +/* APB1 peripheral clock enable register */ + +#define RCC_APB1ENR_DACEN_BIT 29 +#define RCC_APB1ENR_PWREN_BIT 28 +#define RCC_APB1ENR_BKPEN_BIT 27 +#define RCC_APB1ENR_CANEN_BIT 25 +#define RCC_APB1ENR_USBEN_BIT 23 +#define RCC_APB1ENR_I2C2EN_BIT 22 +#define RCC_APB1ENR_I2C1EN_BIT 21 +#define RCC_APB1ENR_UART5EN_BIT 20 +#define RCC_APB1ENR_UART4EN_BIT 19 +#define RCC_APB1ENR_USART3EN_BIT 18 +#define RCC_APB1ENR_USART2EN_BIT 17 +#define RCC_APB1ENR_SPI3EN_BIT 15 +#define RCC_APB1ENR_SPI2EN_BIT 14 +#define RCC_APB1ENR_WWDEN_BIT 11 +#define RCC_APB1ENR_TIM14EN_BIT 8 +#define RCC_APB1ENR_TIM13EN_BIT 7 +#define RCC_APB1ENR_TIM12EN_BIT 6 +#define RCC_APB1ENR_TIM7EN_BIT 5 +#define RCC_APB1ENR_TIM6EN_BIT 4 +#define RCC_APB1ENR_TIM5EN_BIT 3 +#define RCC_APB1ENR_TIM4EN_BIT 2 +#define RCC_APB1ENR_TIM3EN_BIT 1 +#define RCC_APB1ENR_TIM2EN_BIT 0 + +#define RCC_APB1ENR_DACEN (1U << RCC_APB1ENR_DACEN_BIT) +#define RCC_APB1ENR_PWREN (1U << RCC_APB1ENR_PWREN_BIT) +#define RCC_APB1ENR_BKPEN (1U << RCC_APB1ENR_BKPEN_BIT) +#define RCC_APB1ENR_CANEN (1U << RCC_APB1ENR_CANEN_BIT) +#define RCC_APB1ENR_USBEN (1U << RCC_APB1ENR_USBEN_BIT) +#define RCC_APB1ENR_I2C2EN (1U << RCC_APB1ENR_I2C2EN_BIT) +#define RCC_APB1ENR_I2C1EN (1U << RCC_APB1ENR_I2C1EN_BIT) +#define RCC_APB1ENR_UART5EN (1U << RCC_APB1ENR_UART5EN_BIT) +#define RCC_APB1ENR_UART4EN (1U << RCC_APB1ENR_UART4EN_BIT) +#define RCC_APB1ENR_USART3EN (1U << RCC_APB1ENR_USART3EN_BIT) +#define RCC_APB1ENR_USART2EN (1U << RCC_APB1ENR_USART2EN_BIT) +#define RCC_APB1ENR_SPI3EN (1U << RCC_APB1ENR_SPI3EN_BIT) +#define RCC_APB1ENR_SPI2EN (1U << RCC_APB1ENR_SPI2EN_BIT) +#define RCC_APB1ENR_WWDEN (1U << RCC_APB1ENR_WWDEN_BIT) +#define RCC_APB1ENR_TIM14EN (1U << RCC_APB1ENR_TIM14EN_BIT) +#define RCC_APB1ENR_TIM13EN (1U << RCC_APB1ENR_TIM13EN_BIT) +#define RCC_APB1ENR_TIM12EN (1U << RCC_APB1ENR_TIM12EN_BIT) +#define RCC_APB1ENR_TIM7EN (1U << RCC_APB1ENR_TIM7EN_BIT) +#define RCC_APB1ENR_TIM6EN (1U << RCC_APB1ENR_TIM6EN_BIT) +#define RCC_APB1ENR_TIM5EN (1U << RCC_APB1ENR_TIM5EN_BIT) +#define RCC_APB1ENR_TIM4EN (1U << RCC_APB1ENR_TIM4EN_BIT) +#define RCC_APB1ENR_TIM3EN (1U << RCC_APB1ENR_TIM3EN_BIT) +#define RCC_APB1ENR_TIM2EN (1U << RCC_APB1ENR_TIM2EN_BIT) + +/* Backup domain control register */ + +#define RCC_BDCR_BDRST_BIT 16 +#define RCC_BDCR_RTCEN_BIT 15 +#define RCC_BDCR_LSEBYP_BIT 2 +#define RCC_BDCR_LSERDY_BIT 1 +#define RCC_BDCR_LSEON_BIT 0 + +#define RCC_BDCR_BDRST (1U << RCC_BDCR_BDRST_BIT) +#define RCC_BDCR_RTCEN (1U << RCC_BDCR_RTC_BIT) +#define RCC_BDCR_RTCSEL (0x3 << 8) +#define RCC_BDCR_RTCSEL_NONE (0x0 << 8) +#define RCC_BDCR_RTCSEL_LSE (0x1 << 8) +#define RCC_BDCR_RTCSEL_LSI (0x2 << 8) // added to support RTClock +#define RCC_BDCR_RTCSEL_HSE (0x3 << 8) +#define RCC_BDCR_LSEBYP (1U << RCC_BDCR_LSEBYP_BIT) +#define RCC_BDCR_LSERDY (1U << RCC_BDCR_LSERDY_BIT) +#define RCC_BDCR_LSEON (1U << RCC_BDCR_LSEON_BIT) + +/* Control/status register */ + +#define RCC_CSR_LPWRRSTF_BIT 31 +#define RCC_CSR_WWDGRSTF_BIT 30 +#define RCC_CSR_IWDGRSTF_BIT 29 +#define RCC_CSR_SFTRSTF_BIT 28 +#define RCC_CSR_PORRSTF_BIT 27 +#define RCC_CSR_PINRSTF_BIT 26 +#define RCC_CSR_RMVF_BIT 24 +#define RCC_CSR_LSIRDY_BIT 1 +#define RCC_CSR_LSION_BIT 0 + +#define RCC_CSR_LPWRRSTF (1U << RCC_CSR_LPWRRSTF_BIT) +#define RCC_CSR_WWDGRSTF (1U << RCC_CSR_WWDGRSTF_BIT) +#define RCC_CSR_IWDGRSTF (1U << RCC_CSR_IWDGRSTF_BIT) +#define RCC_CSR_SFTRSTF (1U << RCC_CSR_SFTRSTF_BIT) +#define RCC_CSR_PORRSTF (1U << RCC_CSR_PORRSTF_BIT) +#define RCC_CSR_PINRSTF (1U << RCC_CSR_PINRSTF_BIT) +#define RCC_CSR_RMVF (1U << RCC_CSR_RMVF_BIT) +#define RCC_CSR_LSIRDY (1U << RCC_CSR_LSIRDY_BIT) +#define RCC_CSR_LSION (1U << RCC_CSR_LSION_BIT) + +/* + * libmaple-mandated enumeration types. + */ + +/** + * @brief STM32F1 rcc_clk_id. + */ +typedef enum rcc_clk_id { + RCC_ADC1, + RCC_ADC2, + RCC_ADC3, + RCC_AFIO, + RCC_BKP, + RCC_CRC, + RCC_DAC, + RCC_DMA1, + RCC_DMA2, + RCC_FLITF, + RCC_FSMC, + RCC_GPIOA, + RCC_GPIOB, + RCC_GPIOC, + RCC_GPIOD, + RCC_GPIOE, + RCC_GPIOF, + RCC_GPIOG, + RCC_I2C1, + RCC_I2C2, + RCC_PWR, + RCC_SDIO, + RCC_SPI1, + RCC_SPI2, + RCC_SPI3, + RCC_SRAM, + RCC_TIMER1, + RCC_TIMER2, + RCC_TIMER3, + RCC_TIMER4, + RCC_TIMER5, + RCC_TIMER6, + RCC_TIMER7, + RCC_TIMER8, + RCC_TIMER9, + RCC_TIMER10, + RCC_TIMER11, + RCC_TIMER12, + RCC_TIMER13, + RCC_TIMER14, + RCC_USART1, + RCC_USART2, + RCC_USART3, + RCC_UART4, + RCC_UART5, + RCC_USB, + RCC_CAN, //! JMD after X893 +} rcc_clk_id; + +/** + * @brief STM32F1 PLL clock sources. + * @see rcc_configure_pll() + */ +typedef enum rcc_pllsrc { + RCC_PLLSRC_HSE = (0x1 << 16), + RCC_PLLSRC_HSI_DIV_2 = (0x0 << 16) +} rcc_pllsrc; + +/** + * @brief STM32F1 clock domains. + * @see rcc_dev_clk() + */ +typedef enum rcc_clk_domain { + RCC_APB1, + RCC_APB2, + RCC_AHB +} rcc_clk_domain; + +/** + * @brief STM32F1 Prescaler identifiers + * @see rcc_set_prescaler() + */ +typedef enum rcc_prescaler { + RCC_PRESCALER_AHB, + RCC_PRESCALER_APB1, + RCC_PRESCALER_APB2, + RCC_PRESCALER_USB, + RCC_PRESCALER_ADC +} rcc_prescaler; + +/** + * @brief STM32F1 ADC prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum rcc_adc_divider { + RCC_ADCPRE_PCLK_DIV_2 = 0x0 << 14, + RCC_ADCPRE_PCLK_DIV_4 = 0x1 << 14, + RCC_ADCPRE_PCLK_DIV_6 = 0x2 << 14, + RCC_ADCPRE_PCLK_DIV_8 = 0x3 << 14, +} rcc_adc_divider; + +/** + * @brief STM32F1 APB1 prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum rcc_apb1_divider { + RCC_APB1_HCLK_DIV_1 = 0x0 << 8, + RCC_APB1_HCLK_DIV_2 = 0x4 << 8, + RCC_APB1_HCLK_DIV_4 = 0x5 << 8, + RCC_APB1_HCLK_DIV_8 = 0x6 << 8, + RCC_APB1_HCLK_DIV_16 = 0x7 << 8, +} rcc_apb1_divider; + +/** + * @brief STM32F1 APB2 prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum rcc_apb2_divider { + RCC_APB2_HCLK_DIV_1 = 0x0 << 11, + RCC_APB2_HCLK_DIV_2 = 0x4 << 11, + RCC_APB2_HCLK_DIV_4 = 0x5 << 11, + RCC_APB2_HCLK_DIV_8 = 0x6 << 11, + RCC_APB2_HCLK_DIV_16 = 0x7 << 11, +} rcc_apb2_divider; + +/** + * @brief STM32F1 AHB prescaler dividers + * @see rcc_set_prescaler() + */ +typedef enum rcc_ahb_divider { + RCC_AHB_SYSCLK_DIV_1 = 0x0 << 4, + RCC_AHB_SYSCLK_DIV_2 = 0x8 << 4, + RCC_AHB_SYSCLK_DIV_4 = 0x9 << 4, + RCC_AHB_SYSCLK_DIV_8 = 0xA << 4, + RCC_AHB_SYSCLK_DIV_16 = 0xB << 4, + RCC_AHB_SYSCLK_DIV_32 = 0xC << 4, + RCC_AHB_SYSCLK_DIV_64 = 0xD << 4, + RCC_AHB_SYSCLK_DIV_128 = 0xD << 4, + RCC_AHB_SYSCLK_DIV_256 = 0xE << 4, + RCC_AHB_SYSCLK_DIV_512 = 0xF << 4, +} rcc_ahb_divider; + +/** + * @brief STM32F1 USB prescaler dividers + * @see rcc_set_prescaler() + */ + /* + Set and reset by software to control the USB clock prescaler value. The USB clock +must be 48MHz. These bits can’t be reset if the USB clock is enabled. +00: (CK_PLL / 1.5) selected +01: CK_PLL selected + */ + +typedef enum rcc_usb_divider { + RCC_USB_SYSCLK_DIV_1 = 0x1 << 22, + RCC_USB_SYSCLK_DIV_1_5 = 0x0 << 22, + RCC_USB_SYSCLK_DIV_2 = 0x3 << 22, + RCC_USB_SYSCLK_DIV_2_5 = 0x2 << 22, +} rcc_usb_divider; + + +/** + * @brief Start the low speed internal oscillator + */ +static inline void rcc_start_lsi(void) { + *bb_perip(&RCC_BASE->CSR, RCC_CSR_LSION_BIT) = 1; + while (*bb_perip(&RCC_BASE->CSR, RCC_CSR_LSIRDY_BIT) == 0); +} + +/** + * @brief STM32F1 clock sources. + */ +typedef enum rcc_clk { + RCC_CLK_PLL = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | + RCC_CR_PLLON_BIT), /**< Main PLL, clocked by + HSI or HSE. */ + RCC_CLK_HSE = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | + RCC_CR_HSEON_BIT), /**< High speed external. */ + RCC_CLK_HSI = (uint16)((offsetof(struct rcc_reg_map, CR) << 8) | + RCC_CR_HSION_BIT), /**< High speed internal. */ + RCC_CLK_LSE = (uint16)((offsetof(struct rcc_reg_map, BDCR) << 8) | + RCC_BDCR_LSEON_BIT), /**< Low-speed external + * (32.768 KHz). */ + RCC_CLK_LSI = (uint16)((offsetof(struct rcc_reg_map, CSR) << 8) | + RCC_CSR_LSION_BIT), /**< Low-speed internal + * (approximately 32 KHz). */ +} rcc_clk; + +/** + * @brief STM32F1 PLL multipliers. + */ +typedef enum rcc_pll_multiplier { + RCC_PLLMUL_2 = (0x0 << 18), + RCC_PLLMUL_3 = (0x1 << 18), + RCC_PLLMUL_4 = (0x2 << 18), + RCC_PLLMUL_5 = (0x3 << 18), + RCC_PLLMUL_6 = (0x4 << 18), + RCC_PLLMUL_7 = (0x5 << 18), + RCC_PLLMUL_8 = (0x6 << 18), + RCC_PLLMUL_9 = (0x7 << 18), + RCC_PLLMUL_10 = (0x8 << 18), + RCC_PLLMUL_11 = (0x9 << 18), + RCC_PLLMUL_12 = (0xA << 18), + RCC_PLLMUL_13 = (0xB << 18), + RCC_PLLMUL_14 = (0xC << 18), + RCC_PLLMUL_15 = (0xD << 18), + RCC_PLLMUL_16 = (0xE << 18), +} rcc_pll_multiplier; + +/* FIXME [0.0.13] Just have data point to an rcc_pll_multiplier! */ +/** + * @brief Start the low speed external oscillatior + */ +static inline void rcc_start_lse(void) { + bb_peri_set_bit(&RCC_BASE->BDCR, RCC_BDCR_LSEBYP_BIT, 0); + bb_peri_set_bit(&RCC_BASE->BDCR, RCC_BDCR_LSEON_BIT, 1); + while (bb_peri_get_bit(&RCC_BASE->BDCR, RCC_BDCR_LSERDY_BIT ) == 0); +} + +/** + * @brief STM32F1 PLL configuration values. + * Point to one of these with the "data" field in a struct rcc_pll_cfg. + * @see struct rcc_pll_cfg. + */ +typedef struct stm32f1_rcc_pll_data { + rcc_pll_multiplier pll_mul; /**< PLL multiplication factor. */ +} stm32f1_rcc_pll_data; + +/* + * Deprecated bits. + */ +static inline void rcc_start_hse(void) { // Added to support RTClock +// *bb_perip(&RCC_BASE->CR, RCC_CR_HSEON_BIT) = 1; + while (bb_peri_get_bit(&RCC_BASE->CR, RCC_CR_HSERDY_BIT) == 0); +} + +/** + * @brief Deprecated; STM32F1 only. + * + * Initialize the clock control system. Initializes the system + * clock source to use the PLL driven by an external oscillator. + * + * @param sysclk_src system clock source, must be PLL + * @param pll_src pll clock source, must be HSE + * @param pll_mul pll multiplier + */ +__deprecated +void rcc_clk_init(rcc_sysclk_src sysclk_src, + rcc_pllsrc pll_src, + rcc_pll_multiplier pll_mul); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/STM32F1/libraries/rcc_f1.c b/STM32F1/libraries/rcc_f1.c new file mode 100644 index 000000000..9040a4dc2 --- /dev/null +++ b/STM32F1/libraries/rcc_f1.c @@ -0,0 +1,174 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 Perry Hung. + * Copyright (c) 2011 LeafLabs, LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/stm32f1/rcc.c + * @brief STM32F1 RCC. + */ + +#include +#include +#include + +#include "rcc_private.h" + +#define APB1 RCC_APB1 +#define APB2 RCC_APB2 +#define AHB RCC_AHB + +/* Device descriptor table, maps rcc_clk_id onto bus and enable/reset + * register bit numbers. */ +const struct rcc_dev_info rcc_dev_table[] = { + [RCC_GPIOA] = { .clk_domain = APB2, .line_num = 2 }, + [RCC_GPIOB] = { .clk_domain = APB2, .line_num = 3 }, + [RCC_GPIOC] = { .clk_domain = APB2, .line_num = 4 }, + [RCC_GPIOD] = { .clk_domain = APB2, .line_num = 5 }, + [RCC_AFIO] = { .clk_domain = APB2, .line_num = 0 }, + [RCC_ADC1] = { .clk_domain = APB2, .line_num = 9 }, + [RCC_ADC2] = { .clk_domain = APB2, .line_num = 10 }, + [RCC_ADC3] = { .clk_domain = APB2, .line_num = 15 }, + [RCC_USART1] = { .clk_domain = APB2, .line_num = 14 }, + [RCC_USART2] = { .clk_domain = APB1, .line_num = 17 }, + [RCC_USART3] = { .clk_domain = APB1, .line_num = 18 }, + [RCC_TIMER1] = { .clk_domain = APB2, .line_num = 11 }, + [RCC_TIMER2] = { .clk_domain = APB1, .line_num = 0 }, + [RCC_TIMER3] = { .clk_domain = APB1, .line_num = 1 }, + [RCC_TIMER4] = { .clk_domain = APB1, .line_num = 2 }, + [RCC_SPI1] = { .clk_domain = APB2, .line_num = 12 }, + [RCC_SPI2] = { .clk_domain = APB1, .line_num = 14 }, + [RCC_DMA1] = { .clk_domain = AHB, .line_num = 0 }, + [RCC_PWR] = { .clk_domain = APB1, .line_num = 28}, + [RCC_BKP] = { .clk_domain = APB1, .line_num = 27}, + [RCC_I2C1] = { .clk_domain = APB1, .line_num = 21 }, + [RCC_I2C2] = { .clk_domain = APB1, .line_num = 22 }, + [RCC_CRC] = { .clk_domain = AHB, .line_num = 6}, + [RCC_FLITF] = { .clk_domain = AHB, .line_num = 4}, + [RCC_SRAM] = { .clk_domain = AHB, .line_num = 2}, + [RCC_USB] = { .clk_domain = APB1, .line_num = 23}, +#if defined(STM32_HIGH_DENSITY) || defined(STM32_XL_DENSITY) + [RCC_GPIOE] = { .clk_domain = APB2, .line_num = 6 }, + [RCC_GPIOF] = { .clk_domain = APB2, .line_num = 7 }, + [RCC_GPIOG] = { .clk_domain = APB2, .line_num = 8 }, + [RCC_UART4] = { .clk_domain = APB1, .line_num = 19 }, + [RCC_UART5] = { .clk_domain = APB1, .line_num = 20 }, + [RCC_TIMER5] = { .clk_domain = APB1, .line_num = 3 }, + [RCC_TIMER6] = { .clk_domain = APB1, .line_num = 4 }, + [RCC_TIMER7] = { .clk_domain = APB1, .line_num = 5 }, + [RCC_TIMER8] = { .clk_domain = APB2, .line_num = 13 }, + [RCC_FSMC] = { .clk_domain = AHB, .line_num = 8 }, + [RCC_DAC] = { .clk_domain = APB1, .line_num = 29 }, + [RCC_DMA2] = { .clk_domain = AHB, .line_num = 1 }, + [RCC_SDIO] = { .clk_domain = AHB, .line_num = 10 }, + [RCC_SPI3] = { .clk_domain = APB1, .line_num = 15 }, +#endif +#ifdef STM32_XL_DENSITY + [RCC_TIMER9] = { .clk_domain = APB2, .line_num = 19 }, + [RCC_TIMER10] = { .clk_domain = APB2, .line_num = 20 }, + [RCC_TIMER11] = { .clk_domain = APB2, .line_num = 21 }, + [RCC_TIMER12] = { .clk_domain = APB1, .line_num = 6 }, + [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 +void rcc_clk_init(rcc_sysclk_src sysclk_src, + rcc_pllsrc pll_src, + rcc_pll_multiplier pll_mul) { + /* Assume that we're going to clock the chip off the PLL, fed by + * the HSE */ + ASSERT(sysclk_src == RCC_CLKSRC_PLL && + pll_src == RCC_PLLSRC_HSE); + + RCC_BASE->CFGR = pll_src | pll_mul | (0x3<<22); + + /* Turn on, and wait for, HSE. */ + rcc_turn_on_clk(RCC_CLK_HSE); + while (!rcc_is_clk_ready(RCC_CLK_HSE)) + ; + + /* Do the same for the main PLL. */ + rcc_turn_on_clk(RCC_CLK_PLL); + while(!rcc_is_clk_ready(RCC_CLK_PLL)) + ; + + /* Finally, switch over to the PLL. */ + rcc_switch_sysclk(RCC_CLKSRC_PLL); +} + +/* pll_cfg->data must point to a valid struct stm32f1_rcc_pll_data. */ +void rcc_configure_pll(rcc_pll_cfg *pll_cfg) { + stm32f1_rcc_pll_data *data = pll_cfg->data; + rcc_pll_multiplier pll_mul = data->pll_mul; + uint32 cfgr; + /* Check that the PLL is disabled. */ + ASSERT_FAULT(!rcc_is_clk_on(RCC_CLK_PLL)); + + cfgr = RCC_BASE->CFGR; + cfgr &= ~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL); + cfgr |= pll_cfg->pllsrc | pll_mul; + + RCC_BASE->CFGR = cfgr; +} + +void rcc_clk_enable(rcc_clk_id id) { + static __io uint32* enable_regs[] = { + [APB1] = &RCC_BASE->APB1ENR, + [APB2] = &RCC_BASE->APB2ENR, + [AHB] = &RCC_BASE->AHBENR, + }; + rcc_do_clk_enable(enable_regs, id); +} + +void rcc_reset_dev(rcc_clk_id id) { + static __io uint32* reset_regs[] = { + [APB1] = &RCC_BASE->APB1RSTR, + [APB2] = &RCC_BASE->APB2RSTR, + }; + rcc_do_reset_dev(reset_regs, id); +} + +void rcc_set_prescaler(rcc_prescaler prescaler, uint32 divider) { + static const uint32 masks[] = { + [RCC_PRESCALER_AHB] = RCC_CFGR_HPRE, + [RCC_PRESCALER_APB1] = RCC_CFGR_PPRE1, + [RCC_PRESCALER_APB2] = RCC_CFGR_PPRE2, + [RCC_PRESCALER_USB] = RCC_CFGR_USBPRE, + [RCC_PRESCALER_ADC] = RCC_CFGR_ADCPRE, + }; + rcc_do_set_prescaler(masks, prescaler, divider); +} + +void rcc_clk_disable(rcc_clk_id id) { + static __io uint32* enable_regs[] = { + [APB1] = &RCC_BASE->APB1ENR, + [APB2] = &RCC_BASE->APB2ENR, + [AHB] = &RCC_BASE->AHBENR, + }; + rcc_do_clk_disable(enable_regs, id); +} \ No newline at end of file diff --git a/STM32F1/libraries/usb.c b/STM32F1/libraries/usb.c new file mode 100644 index 000000000..f7965351a --- /dev/null +++ b/STM32F1/libraries/usb.c @@ -0,0 +1,402 @@ +/****************************************************************************** + * The MIT License + * + * Copyright (c) 2010 LeafLabs LLC. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + *****************************************************************************/ + +/** + * @file libmaple/usb/stm32f1/usb.c + * @brief USB support. + * + * This is a mess. + */ + +#include + +#include +#include + +/* Private headers */ +#include "usb_reg_map.h" +#include "usb_lib_globals.h" + +/* usb_lib headers */ +#include "usb_type.h" +#include "usb_core.h" + +static void dispatch_ctr_lp(void); + +/* + * usb_lib/ globals + */ + +uint16 SaveTState; /* caches TX status for later use */ +uint16 SaveRState; /* caches RX status for later use */ + +/* + * Other state + */ + +typedef enum { + RESUME_EXTERNAL, + RESUME_INTERNAL, + RESUME_LATER, + RESUME_WAIT, + RESUME_START, + RESUME_ON, + RESUME_OFF, + RESUME_ESOF +} RESUME_STATE; + +struct { + volatile RESUME_STATE eState; + volatile uint8 bESOFcnt; +} ResumeS; + +static usblib_dev usblib = { + .irq_mask = USB_ISR_MSK, + .state = USB_UNCONNECTED, + .prevState = USB_UNCONNECTED, + .clk_id = RCC_USB, +}; +usblib_dev *USBLIB = &usblib; + +/* + * Routines + */ + +void usb_init_usblib(usblib_dev *dev, + void (**ep_int_in)(void), + void (**ep_int_out)(void)) { + rcc_clk_enable(dev->clk_id); + + dev->ep_int_in = ep_int_in; + dev->ep_int_out = ep_int_out; + + /* usb_lib/ declares both and then assumes that pFoo points to Foo + * (even though the names don't always match), which is stupid for + * all of the obvious reasons, but whatever. Here we are. */ + pInformation = &Device_Info; + pProperty = &Device_Property; + pUser_Standard_Requests = &User_Standard_Requests; + + pInformation->ControlState = 2; /* FIXME [0.0.12] use + CONTROL_STATE enumerator */ + pProperty->Init(); +} + +static void usb_suspend(void) { + uint16 cntr; + + /* TODO decide if read/modify/write is really what we want + * (e.g. usb_resume_init() reconfigures CNTR). */ + cntr = USB_BASE->CNTR; + cntr |= USB_CNTR_FSUSP; + USB_BASE->CNTR = cntr; + cntr |= USB_CNTR_LP_MODE; + USB_BASE->CNTR = cntr; + + USBLIB->prevState = USBLIB->state; + USBLIB->state = USB_SUSPENDED; +} + +static void usb_resume_init(void) { + uint16 cntr; + + cntr = USB_BASE->CNTR; + cntr &= ~USB_CNTR_LP_MODE; + USB_BASE->CNTR = cntr; + + /* Enable interrupt lines */ + USB_BASE->CNTR = USB_ISR_MSK; +} + +static void usb_resume(RESUME_STATE eResumeSetVal) { + uint16 cntr; + + if (eResumeSetVal != RESUME_ESOF) { + ResumeS.eState = eResumeSetVal; + } + + switch (ResumeS.eState) { + case RESUME_EXTERNAL: + usb_resume_init(); + ResumeS.eState = RESUME_OFF; + USBLIB->state = USBLIB->prevState; + break; + case RESUME_INTERNAL: + usb_resume_init(); + ResumeS.eState = RESUME_START; + break; + case RESUME_LATER: + ResumeS.bESOFcnt = 2; + ResumeS.eState = RESUME_WAIT; + break; + case RESUME_WAIT: + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) { + ResumeS.eState = RESUME_START; + } + break; + case RESUME_START: + cntr = USB_BASE->CNTR; + cntr |= USB_CNTR_RESUME; + USB_BASE->CNTR = cntr; + ResumeS.eState = RESUME_ON; + ResumeS.bESOFcnt = 10; + break; + case RESUME_ON: + ResumeS.bESOFcnt--; + if (ResumeS.bESOFcnt == 0) { + cntr = USB_BASE->CNTR; + cntr &= ~USB_CNTR_RESUME; + USB_BASE->CNTR = cntr; + USBLIB->state = USBLIB->prevState; + ResumeS.eState = RESUME_OFF; + } + break; + case RESUME_OFF: + case RESUME_ESOF: + default: + ResumeS.eState = RESUME_OFF; + break; + } +} + +// 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) + if (istr & USB_ISTR_RESET & USBLIB->irq_mask) { + USB_BASE->ISTR = ~USB_ISTR_RESET; + pProperty->Reset(); + } +#endif + +#if (USB_ISR_MSK & USB_ISTR_PMAOVR) + if (istr & ISTR_PMAOVR & USBLIB->irq_mask) { + USB_BASE->ISTR = ~USB_ISTR_PMAOVR; + } +#endif + +#if (USB_ISR_MSK & USB_ISTR_ERR) + if (istr & USB_ISTR_ERR & USBLIB->irq_mask) { + USB_BASE->ISTR = ~USB_ISTR_ERR; + } +#endif + +#if (USB_ISR_MSK & USB_ISTR_WKUP) + if (istr & USB_ISTR_WKUP & USBLIB->irq_mask) { + USB_BASE->ISTR = ~(USB_ISTR_WKUP | USB_ISTR_SUSP); + usb_resume(RESUME_EXTERNAL); + } +#endif + +#if (USB_ISR_MSK & USB_ISTR_SUSP) + if (istr & USB_ISTR_SUSP & USBLIB->irq_mask) { + /* check if SUSPEND is possible */ + if (SUSPEND_ENABLED) { + usb_suspend(); + } else { + /* if not possible then resume after xx ms */ + usb_resume(RESUME_LATER); + } + /* clear of the ISTR bit must be done after setting of CNTR_FSUSP */ + USB_BASE->ISTR = ~(USB_ISTR_WKUP | USB_ISTR_SUSP); + } +#endif + +#if (USB_ISR_MSK & USB_ISTR_SOF) + if (istr & USB_ISTR_SOF & USBLIB->irq_mask) { + USB_BASE->ISTR = ~USB_ISTR_SOF; + } +#endif + +#if (USB_ISR_MSK & USB_ISTR_ESOF) + if (istr & USB_ISTR_ESOF & USBLIB->irq_mask) { + USB_BASE->ISTR = ~USB_ISTR_ESOF; + /* resume handling timing is made with ESOFs */ + usb_resume(RESUME_ESOF); /* request without change of the machine state */ + } +#endif + + /* + * Service the correct transfer interrupt. + */ + +#if (USB_ISR_MSK & USB_ISTR_CTR) + if (istr & USB_ISTR_CTR & USBLIB->irq_mask) { + dispatch_ctr_lp(); + } +#endif +} + +/* + * Auxiliary routines + */ + +static inline uint8 dispatch_endpt_zero(uint16 istr_dir); +static inline void dispatch_endpt(uint8 ep); +static inline void set_rx_tx_status0(uint16 rx, uint16 tx); + +static void handle_setup0(void); +static void handle_in0(void); +static void handle_out0(void); + +static void dispatch_ctr_lp() { + uint16 istr; + while (((istr = USB_BASE->ISTR) & USB_ISTR_CTR) != 0) { + /* TODO WTF, figure this out: RM0008 says CTR is read-only, + * but ST's firmware claims it's clear-only, and emphasizes + * the importance of clearing it in more than one place. */ + USB_BASE->ISTR = ~USB_ISTR_CTR; + uint8 ep_id = istr & USB_ISTR_EP_ID; + if (ep_id == 0) { + /* TODO figure out why it's OK to break out of the loop + * once we're done serving endpoint zero, but not okay if + * there are multiple nonzero endpoint transfers to + * handle. */ + if (dispatch_endpt_zero(istr & USB_ISTR_DIR)) { + return; + } + } else { + dispatch_endpt(ep_id); + } + } +} + +/* FIXME Dataflow on endpoint 0 RX/TX status is based off of ST's + * code, and is ugly/confusing in its use of SaveRState/SaveTState. + * Fixing this requires filling in handle_in0(), handle_setup0(), + * handle_out0(). */ +static inline uint8 dispatch_endpt_zero(uint16 istr_dir) { + uint32 epr = (uint16)USB_BASE->EP[0]; + + if (!(epr & (USB_EP_CTR_TX | USB_EP_SETUP | USB_EP_CTR_RX))) { + return 0; + } + + /* Cache RX/TX statuses in SaveRState/SaveTState, respectively. + * The various handle_foo0() may clobber these values + * before we reset them at the end of this routine. */ + SaveRState = epr & USB_EP_STAT_RX; + SaveTState = epr & USB_EP_STAT_TX; + + /* Set actual RX/TX statuses to NAK while we're thinking */ + set_rx_tx_status0(USB_EP_STAT_RX_NAK, USB_EP_STAT_TX_NAK); + + if (istr_dir == 0) { + /* ST RM0008: "If DIR bit=0, CTR_TX bit is set in the USB_EPnR + * register related to the interrupting endpoint. The + * interrupting transaction is of IN type (data transmitted by + * the USB peripheral to the host PC)." */ + ASSERT_FAULT(epr & USB_EP_CTR_TX); + usb_clear_ctr_tx(USB_EP0); + handle_in0(); + } else { + /* RM0008: "If DIR bit=1, CTR_RX bit or both CTR_TX/CTR_RX + * are set in the USB_EPnR register related to the + * interrupting endpoint. The interrupting transaction is of + * OUT type (data received by the USB peripheral from the host + * PC) or two pending transactions are waiting to be + * processed." + * + * [mbolivar] Note how the following control flow (which + * replicates ST's) doesn't seem to actually handle both + * interrupts that are ostensibly pending when both CTR_RX and + * CTR_TX are set. + * + * TODO sort this mess out. + */ + if (epr & USB_EP_CTR_TX) { + usb_clear_ctr_tx(USB_EP0); + handle_in0(); + } else { /* SETUP or CTR_RX */ + /* SETUP is held constant while CTR_RX is set, so clear it + * either way */ + usb_clear_ctr_rx(USB_EP0); + if (epr & USB_EP_SETUP) { + handle_setup0(); + } else { /* CTR_RX */ + handle_out0(); + } + } + } + + set_rx_tx_status0(SaveRState, SaveTState); + return 1; +} + +static inline void dispatch_endpt(uint8 ep) { + uint32 epr = USB_BASE->EP[ep]; + /* If ISTR_CTR is set and the ISTR gave us this EP_ID to handle, + * then presumably at least one of CTR_RX and CTR_TX is set, but + * again, ST's control flow allows for the possibility of neither. + * + * TODO try to find out if neither being set is possible. */ + if (epr & USB_EP_CTR_RX) { + usb_clear_ctr_rx(ep); + (USBLIB->ep_int_out[ep - 1])(); + } + if (epr & USB_EP_CTR_TX) { + usb_clear_ctr_tx(ep); + (USBLIB->ep_int_in[ep - 1])(); + } +} + +static inline void set_rx_tx_status0(uint16 rx, uint16 tx) { + usb_set_ep_rx_stat(USB_EP0, rx); + usb_set_ep_tx_stat(USB_EP0, tx); +} + +/* TODO Rip out usb_lib/ dependency from the following functions: */ + +static void handle_setup0(void) { + Setup0_Process(); +} + +static void handle_in0(void) { + In0_Process(); +} + +static void handle_out0(void) { + Out0_Process(); +} From ee3a3056146dd188b0a2e43261cd1fd3d348edbe Mon Sep 17 00:00:00 2001 From: Phonog Date: Mon, 31 Oct 2016 22:33:52 +0100 Subject: [PATCH 02/18] Add files via upload --- STM32F1/cores/maple/libmaple/rcc_f1.c | 1 + 1 file changed, 1 insertion(+) diff --git a/STM32F1/cores/maple/libmaple/rcc_f1.c b/STM32F1/cores/maple/libmaple/rcc_f1.c index f45f670e1..9040a4dc2 100644 --- a/STM32F1/cores/maple/libmaple/rcc_f1.c +++ b/STM32F1/cores/maple/libmaple/rcc_f1.c @@ -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 From 9765b9b36883e8edae546ea96d95597ad0fd0740 Mon Sep 17 00:00:00 2001 From: Phonog Date: Mon, 31 Oct 2016 22:35:35 +0100 Subject: [PATCH 03/18] Add files via upload --- STM32F1/system/libmaple/stm32f1/include/series/rcc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/STM32F1/system/libmaple/stm32f1/include/series/rcc.h b/STM32F1/system/libmaple/stm32f1/include/series/rcc.h index f40dcbaba..aa9f8d3c9 100644 --- a/STM32F1/system/libmaple/stm32f1/include/series/rcc.h +++ b/STM32F1/system/libmaple/stm32f1/include/series/rcc.h @@ -439,6 +439,7 @@ typedef enum rcc_clk_id { RCC_UART4, RCC_UART5, RCC_USB, + RCC_CAN, //! JMD after X893 } rcc_clk_id; /** From 9e5911b98f6239245a7dbb2da7dc9667939aebfd Mon Sep 17 00:00:00 2001 From: Phonog Date: Mon, 31 Oct 2016 23:05:27 +0100 Subject: [PATCH 04/18] Add files via upload --- STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c index f837eb64b..f7965351a 100644 --- a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c +++ b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c @@ -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) From 46da53e4259d5643ab9a0aee24ea12a2f1471bd8 Mon Sep 17 00:00:00 2001 From: megadrifter Date: Fri, 16 Dec 2016 09:05:23 +0300 Subject: [PATCH 05/18] added the simplified send example also added testing sketch for GM LAN. --- .../AstraH_CAN_test/AstraH_CAN_test.ino | 145 ++++++++++++++++++ .../HardwareCAN_simplified_send1.ino | 93 +++++++++++ 2 files changed, 238 insertions(+) create mode 100644 STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test.ino create mode 100644 STM32F1/libraries/HardwareCAN/examples/HardwareCAN_simplified_send1/HardwareCAN_simplified_send1.ino diff --git a/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test.ino b/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test.ino new file mode 100644 index 000000000..a05576bb9 --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test.ino @@ -0,0 +1,145 @@ +#include +/* + * 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(); + } + + +} diff --git a/STM32F1/libraries/HardwareCAN/examples/HardwareCAN_simplified_send1/HardwareCAN_simplified_send1.ino b/STM32F1/libraries/HardwareCAN/examples/HardwareCAN_simplified_send1/HardwareCAN_simplified_send1.ino new file mode 100644 index 000000000..17fb07f9b --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/examples/HardwareCAN_simplified_send1/HardwareCAN_simplified_send1.ino @@ -0,0 +1,93 @@ +#include +//#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++; +} From 51eb06419435443ab35af16652a80267d54f4032 Mon Sep 17 00:00:00 2001 From: megadrifter Date: Fri, 16 Dec 2016 09:08:21 +0300 Subject: [PATCH 06/18] Add 33 and 95 kbps speeds --- STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp | 2 ++ STM32F1/libraries/HardwareCAN/src/utility/can.c | 12 ++++++++++++ STM32F1/libraries/HardwareCAN/src/utility/can.h | 2 ++ 3 files changed, 16 insertions(+) diff --git a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp index f113c4d85..f324e865f 100644 --- a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp +++ b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp @@ -13,6 +13,8 @@ * - CAN_SPEED_500 * - CAN_SPEED_250 * - CAN_SPEED_125 + * - CAN_SPEED_95 + * - CAN_SPEED_33 */ CAN_STATUS HardwareCAN::begin(CAN_SPEED speed, uint32 mode) { diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.c b/STM32F1/libraries/HardwareCAN/src/utility/can.c index 0120e0eed..2f924184a 100644 --- a/STM32F1/libraries/HardwareCAN/src/utility/can.c +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.c @@ -44,6 +44,18 @@ struct can_speed_info { #define CAN_CLOCK (36000000UL / 18UL) static const struct can_speed_info can_speed_table[] = { + [CAN_SPEED_33] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 33000UL - 1) + )}, + [CAN_SPEED_95] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 95000UL - 1) + )}, [CAN_SPEED_125] = { .btr = ( (( 4-1) << CAN_BTR_SJW_POS) | ((12-1) << CAN_BTR_TS1_POS) | diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.h b/STM32F1/libraries/HardwareCAN/src/utility/can.h index 576ac36fe..972259d3d 100644 --- a/STM32F1/libraries/HardwareCAN/src/utility/can.h +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.h @@ -168,6 +168,8 @@ typedef enum CAN_TX_MBX #define CAN_MODE_SILENT_LOOPBACK (CAN_BTR_LBKM | CAN_BTR_SILM) /* loopback combined with silent mode */ enum CAN_SPEED { + CAN_SPEED_33, + CAN_SPEED_95, CAN_SPEED_125, CAN_SPEED_250, CAN_SPEED_500, From 2c37a9ea1efa8e7257677a84defeed63693f59a5 Mon Sep 17 00:00:00 2001 From: megadrifter Date: Fri, 24 Mar 2017 22:36:44 +0300 Subject: [PATCH 07/18] RPM reading example Example says when you need to shift up or shift down --- .../AstraH_CAN_test/AstraH_CAN_test_rpm.ino | 180 ++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test_rpm.ino diff --git a/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test_rpm.ino b/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test_rpm.ino new file mode 100644 index 000000000..0ea0b3a29 --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test_rpm.ino @@ -0,0 +1,180 @@ +#include +/* + * Uses STM32duino with Phono patch. Must add 33 and 95 CAN speeds + */ +#define BPIN 0 // there is a buttton +#define SPIN 1 // there is a switch +#define BUZZERPIN 17 // B1 for buzzer + +// Instanciation of CAN interface +HardwareCAN canBus(CAN1_BASE); +CanMsg msg ; +CanMsg *r_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_33, CAN_MODE_NORMAL); + + 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 +bool bState = 0; // variable for reading the pushbutton status +bool 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); // LED + pinMode(BPIN, INPUT); // input for hardware button + pinMode(SPIN, INPUT); // input for hardware switch + + Serial.begin(115200); + pinMode(BUZZERPIN, OUTPUT); + digitalWrite(BUZZERPIN, LOW); + + Serial1.begin(115200); + Serial1.println("Hello World!"); +} + +void beep(int times) +{ + for (int i=0;iID) == 0x108 ) { + Serial1.println("Data read at 0x108"); + byte tt = r_msg->Data[0]; + byte xx = r_msg->Data[1]; + byte yy = r_msg->Data[2]; + int rpm = (xx<<6) + (yy>>2); + Serial1.print("rpm = "); + Serial1.println(rpm); + if (tt&0x20){ /* Throttle on? */ + Serial1.println("Throttle ON"); + if (xx > 0x2e) {beep(2); Serial1.println("Shift up!");} + if (xx < 0x1c) {beep(1); Serial1.println("Shift down!");} + } + gotit = 1; + } + canBus.free(); + } + /* --- End check RPMs --- */ + } + else + { + // 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]); + } + + canBus.free(); + } + + + +} From def81887c18071e6d75fff1eef58567bd08c795d Mon Sep 17 00:00:00 2001 From: megadrifter Date: Sat, 25 Mar 2017 12:30:07 +0300 Subject: [PATCH 08/18] corrected mistakes From 89efb6e32ce6417b4bdb409add59771d08384d89 Mon Sep 17 00:00:00 2001 From: megadrifter Date: Thu, 1 Jun 2017 18:49:26 +0300 Subject: [PATCH 09/18] add CAN_GPIO_PA11_PA12 --- STM32F1/libraries/HardwareCAN/src/utility/can.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.h b/STM32F1/libraries/HardwareCAN/src/utility/can.h index 972259d3d..19506ea85 100644 --- a/STM32F1/libraries/HardwareCAN/src/utility/can.h +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.h @@ -139,7 +139,8 @@ extern "C" { typedef enum CAN_GPIO_MAP { CAN_GPIO_PB8_PB9, /* RX to PB8, TX to PB9 */ - CAN_GPIO_PD0_PD1 /* RX to PD0, TX to PD1 */ + CAN_GPIO_PD0_PD1, /* RX to PD0, TX to PD1 */ + CAN_GPIO_PA11_PA12 /* RX to PA11, TX to PA12 */ } CAN_GPIO_MAP; typedef enum CAN_STATUS From 222b15be05289b1c521fd5ba05b055822fcede81 Mon Sep 17 00:00:00 2001 From: megadrifter Date: Thu, 1 Jun 2017 18:53:00 +0300 Subject: [PATCH 10/18] add A11-A12 REMAP --- STM32F1/libraries/HardwareCAN/src/utility/can.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.c b/STM32F1/libraries/HardwareCAN/src/utility/can.c index 2f924184a..ad7a7da59 100644 --- a/STM32F1/libraries/HardwareCAN/src/utility/can.c +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.c @@ -257,6 +257,12 @@ CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode) gpio_set_mode(GPIOB, 8, GPIO_INPUT_FLOATING); gpio_set_mode(GPIOB, 9, GPIO_AF_OUTPUT_PP); break; + case CAN_GPIO_PA11_PA12: + rcc_clk_enable(RCC_GPIOA); + afio_remap(AFIO_MAPR_CAN_REMAP_NONE); + gpio_set_mode(GPIOA, 11, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOA, 12, GPIO_AF_OUTPUT_PP); + break; #if NR_GPIO_PORTS >= 4 case CAN_GPIO_PD0_PD1: rcc_clk_enable(RCC_GPIOD); From fe9039c9e0e6b78ccb6975151b5fc6e46e3a8031 Mon Sep 17 00:00:00 2001 From: megadrifter Date: Wed, 7 Jun 2017 19:52:52 +0300 Subject: [PATCH 11/18] add real timer setting as mcs/72 --- STM32F1/cores/maple/HardwareTimer.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/STM32F1/cores/maple/HardwareTimer.h b/STM32F1/cores/maple/HardwareTimer.h index 45272ec0b..ea390f9ae 100644 --- a/STM32F1/cores/maple/HardwareTimer.h +++ b/STM32F1/cores/maple/HardwareTimer.h @@ -142,6 +142,18 @@ class HardwareTimer { * greater than zero. * @return The new overflow value. */ + uint16 setPeriod72(uint32 microseconds); + /** + * @brief Set the timer's period in microseconds/72. + * + * Configures the prescaler and overflow values to generate a timer + * reload with a period as close to the given number of + * microseconds as possible. + * + * @param microseconds The desired period of the timer. This must be + * greater than zero. + * @return The new overflow value. + */ uint16 setPeriod(uint32 microseconds); /** From f7229a7b0920757cc9ca770ca600aa72be5a50df Mon Sep 17 00:00:00 2001 From: megadrifter Date: Wed, 7 Jun 2017 19:58:00 +0300 Subject: [PATCH 12/18] add setCycles to use instead of setPeriod because I neet faster interrupt than 1 microsecond. --- STM32F1/cores/maple/HardwareTimer.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/STM32F1/cores/maple/HardwareTimer.cpp b/STM32F1/cores/maple/HardwareTimer.cpp index 48d040037..676ad3743 100644 --- a/STM32F1/cores/maple/HardwareTimer.cpp +++ b/STM32F1/cores/maple/HardwareTimer.cpp @@ -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); } From 58e70e68514e352d0ba2de318e5250108218fff9 Mon Sep 17 00:00:00 2001 From: megadrifter Date: Wed, 7 Jun 2017 20:01:55 +0300 Subject: [PATCH 13/18] rename to setCycles function --- STM32F1/cores/maple/HardwareTimer.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/STM32F1/cores/maple/HardwareTimer.h b/STM32F1/cores/maple/HardwareTimer.h index ea390f9ae..9fa1ca3ff 100644 --- a/STM32F1/cores/maple/HardwareTimer.h +++ b/STM32F1/cores/maple/HardwareTimer.h @@ -132,19 +132,19 @@ class HardwareTimer { void setCount(uint16 val); /** - * @brief Set the timer's period in microseconds. + * @brief Set the timer's period in Cycles. * * Configures the prescaler and overflow values to generate a timer - * reload with a period as close to the given number of - * microseconds as possible. + * reload with a period of given number of + * Cycles. * - * @param microseconds The desired period of the timer. This must be + * @param Cycles The desired period of the timer. This must be * greater than zero. * @return The new overflow value. */ - uint16 setPeriod72(uint32 microseconds); + uint16 setCycles(uint32 Cycles); /** - * @brief Set the timer's period in microseconds/72. + * @brief Set the timer's period in microseconds. * * Configures the prescaler and overflow values to generate a timer * reload with a period as close to the given number of From 87d36842299a3950b7b17b2c34c74e4385c64775 Mon Sep 17 00:00:00 2001 From: Drifter Date: Thu, 8 Jun 2017 08:53:03 +0300 Subject: [PATCH 14/18] =Add dual CAN example --- .../AstraH_CAN_test/AstraH_CAN_test_rpm.ino | 180 ------------------ .../examples/STMdualCAN/STMdualCAN.ino | 123 ++++++++++++ 2 files changed, 123 insertions(+), 180 deletions(-) delete mode 100644 STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test_rpm.ino create mode 100644 STM32F1/libraries/HardwareCAN/examples/STMdualCAN/STMdualCAN.ino diff --git a/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test_rpm.ino b/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test_rpm.ino deleted file mode 100644 index 0ea0b3a29..000000000 --- a/STM32F1/libraries/HardwareCAN/examples/AstraH_CAN_test/AstraH_CAN_test_rpm.ino +++ /dev/null @@ -1,180 +0,0 @@ -#include -/* - * Uses STM32duino with Phono patch. Must add 33 and 95 CAN speeds - */ -#define BPIN 0 // there is a buttton -#define SPIN 1 // there is a switch -#define BUZZERPIN 17 // B1 for buzzer - -// Instanciation of CAN interface -HardwareCAN canBus(CAN1_BASE); -CanMsg msg ; -CanMsg *r_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_33, CAN_MODE_NORMAL); - - 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 -bool bState = 0; // variable for reading the pushbutton status -bool 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); // LED - pinMode(BPIN, INPUT); // input for hardware button - pinMode(SPIN, INPUT); // input for hardware switch - - Serial.begin(115200); - pinMode(BUZZERPIN, OUTPUT); - digitalWrite(BUZZERPIN, LOW); - - Serial1.begin(115200); - Serial1.println("Hello World!"); -} - -void beep(int times) -{ - for (int i=0;iID) == 0x108 ) { - Serial1.println("Data read at 0x108"); - byte tt = r_msg->Data[0]; - byte xx = r_msg->Data[1]; - byte yy = r_msg->Data[2]; - int rpm = (xx<<6) + (yy>>2); - Serial1.print("rpm = "); - Serial1.println(rpm); - if (tt&0x20){ /* Throttle on? */ - Serial1.println("Throttle ON"); - if (xx > 0x2e) {beep(2); Serial1.println("Shift up!");} - if (xx < 0x1c) {beep(1); Serial1.println("Shift down!");} - } - gotit = 1; - } - canBus.free(); - } - /* --- End check RPMs --- */ - } - else - { - // 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]); - } - - canBus.free(); - } - - - -} diff --git a/STM32F1/libraries/HardwareCAN/examples/STMdualCAN/STMdualCAN.ino b/STM32F1/libraries/HardwareCAN/examples/STMdualCAN/STMdualCAN.ino new file mode 100644 index 000000000..cbeaf8962 --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/examples/STMdualCAN/STMdualCAN.ino @@ -0,0 +1,123 @@ +#include +/* + * + */ + +#define T_DELAY 10 +// Instanciation of CAN interface +HardwareCAN canBus(CAN1_BASE); +CanMsg msg ; + + +void CAN_a_33_Setup(void) +{ + + CAN_STATUS Stat ; + afio_init(); // this will restart subsystem and make it work! + canBus.map(CAN_GPIO_PA11_PA12); + Stat = canBus.begin(CAN_SPEED_33, CAN_MODE_NORMAL); + canBus.filter(0, 0, 0); + canBus.set_irq_mode(); + Stat = canBus.status(); + if (Stat != CAN_OK) + {digitalWrite(PC13, LOW); + } +// /* Your own error processing here */ ; // Initialization failed + } + +void CAN_b_95_Setup(void) +{ + CAN_STATUS Stat ; + canBus.map(CAN_GPIO_PB8_PB9); + Stat = canBus.begin(CAN_SPEED_95, CAN_MODE_NORMAL); + canBus.filter(0, 0, 0); + canBus.set_irq_mode(); + Stat = canBus.status(); + if (Stat != CAN_OK) + {digitalWrite(PC13, LOW); + } +// /* Your own error processing here */ ; // Initialization failed +// delay(T_DELAY); +} + + +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 + digitalWrite(PC13, HIGH); // turn the LED off + delay(T_DELAY); +} + + +// The application program starts here +byte msgD0 = 0x00; +void setup() { // Initialize the CAN module and prepare the message structures. + pinMode(PC13, OUTPUT); + digitalWrite(PC13, HIGH); + delay(10); + digitalWrite(PC13, LOW); + delay(200); + digitalWrite(PC13, HIGH); + delay(200); + +} + + +void loop() { +/**/ + CAN_a_33_Setup(); + SendCANmessage(0x108,8,0x03,msgD0,msgD0,0x00,msgD0,msgD0,0x00,0x00); + SendCANmessage(0x5e8,8,0x81,msgD0,msgD0,msgD0); + delay(30); +/**/ + CAN_b_95_Setup(); + for (byte msgD1=1;msgD1<3;msgD1++) + { + delay(T_DELAY); + SendCANmessage(0x201,3,0x01,0xff,msgD0); + delay(T_DELAY); + SendCANmessage(0x201,3,0x00,0xff,msgD0); + delay(T_DELAY); + SendCANmessage(0x201,3,0x01,0xff,msgD1); + delay(T_DELAY); + SendCANmessage(0x201,3,0x00,0xff,msgD1); + delay(T_DELAY); + } +/**/ +msgD0++; +} From a9807d2a77d05d177e7d7140bbaf9689713c92d0 Mon Sep 17 00:00:00 2001 From: megadrifter Date: Wed, 13 Sep 2017 22:59:56 +0300 Subject: [PATCH 15/18] CAN filter corrected by tjb12345 http://www.stm32duino.com/viewtopic.php?p=34279#p34295 --- STM32F1/libraries/HardwareCAN/src/utility/can.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.c b/STM32F1/libraries/HardwareCAN/src/utility/can.c index ad7a7da59..954e6e349 100644 --- a/STM32F1/libraries/HardwareCAN/src/utility/can.c +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.c @@ -279,7 +279,7 @@ CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode) return status; } -CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2) +CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2, int extID = 0) { uint32 mask = ((uint32)0x00000001) << filter_idx; @@ -291,9 +291,15 @@ CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTE CANx->FS1R |= mask; else CANx->FS1R &= ~mask; - - CANx->sFilterRegister[filter_idx].FR1 = fr1; - CANx->sFilterRegister[filter_idx].FR2 = fr2; + if (extID) { + CANx->sFilterRegister[filter_idx].FR1 = (fr1 << 3) | CAN_ID_EXT; + CANx->sFilterRegister[filter_idx].FR2 = (fr2 << 3) | CAN_ID_EXT; + } + else { + CANx->sFilterRegister[filter_idx].FR1 = (fr1 << 21); + CANx->sFilterRegister[filter_idx].FR2 = (fr2 << 21); + } + if (mode == CAN_FILTER_MASK) CANx->FM1R &= ~mask; @@ -309,7 +315,6 @@ CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTE CANx->FMR &= ~CAN_FMR_FINIT; return CAN_OK; } - /** * @brief Initiates the transmission of a message. * @param CANx: where x can be 1 to select the CAN peripheral. From 99d8b78a24c458bc1cabc3a3d5047beda1561600 Mon Sep 17 00:00:00 2001 From: megadrifter Date: Fri, 13 Oct 2017 14:09:31 +0300 Subject: [PATCH 16/18] latest files from Phonog --- .../libraries/HardwareCAN/src/utility/can.c | 66 +- .../HardwareCAN/src/utility/can.c.txt | 591 +++++++++++++++++ .../libraries/HardwareCAN/src/utility/can.h | 1 + .../HardwareCAN/src/utility/can.temp.c | 599 ++++++++++++++++++ 4 files changed, 1238 insertions(+), 19 deletions(-) create mode 100644 STM32F1/libraries/HardwareCAN/src/utility/can.c.txt create mode 100644 STM32F1/libraries/HardwareCAN/src/utility/can.temp.c diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.c b/STM32F1/libraries/HardwareCAN/src/utility/can.c index 0120e0eed..ce203a4c7 100644 --- a/STM32F1/libraries/HardwareCAN/src/utility/can.c +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.c @@ -1,9 +1,4 @@ -//#include "libmaple.h" #include "can.h" -//#include "rcc.h" -//#include "gpio.h" -//#include "nvic.h" -//#include "usb.h" /** * CAN_interrupts @@ -73,10 +68,10 @@ static const struct can_speed_info can_speed_table[] = { CAN_STATUS status; CanMsg can_rx_queue[CAN_RX_QUEUE_SIZE]; -uint8 can_rx_head; -uint8 can_rx_tail; -uint8 can_rx_count; -uint8 can_rx_lost; +// JMD 2017/07/18 -- added volatile to fix queue problems, removed can_rx_count +volatile uint8 can_rx_head; +volatile uint8 can_rx_tail; +volatile uint8 can_rx_lost; uint8 can_active = 0; /** @@ -137,7 +132,10 @@ CAN_STATUS can_deinit(CAN_Port* CANx) if (CANx == CAN1_BASE) { nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // Disable interrupts + nvic_irq_disable(NVIC_CAN_RX1); nvic_irq_disable(NVIC_USB_HP_CAN_TX); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective rcc_reset_dev(RCC_CAN); rcc_clk_disable(RCC_CAN); can_active = 0; @@ -161,11 +159,10 @@ CAN_STATUS can_init(CAN_Port* CANx, uint32 control, uint8 speed) { status = CAN_INIT_FAILED; // default result status // initialize receive message queue - can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; + can_rx_head = can_rx_tail = can_rx_lost = 0; rcc_reset_dev(RCC_USB); //! X893 rcc_clk_disable(RCC_USB); //! X893 -// line_dtr_rts = 0; //! X893 rcc_clk_enable(RCC_AFIO); // enable clocks for AFIO rcc_clk_enable(RCC_CAN); // and CAN rcc_reset_dev(RCC_CAN); // reset CAN interface @@ -184,6 +181,7 @@ CAN_STATUS can_init(CAN_Port* CANx, uint32 control, uint8 speed) CANx->BTR |= (can_speed_table[speed].btr & CAN_TIMING_MASK); nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // Enable interrupts + nvic_irq_enable(NVIC_CAN_RX1); nvic_irq_enable(NVIC_USB_HP_CAN_TX); @@ -292,6 +290,7 @@ CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTE return CAN_OK; } + /** * @brief Initiates the transmission of a message. * @param CANx: where x can be 1 to select the CAN peripheral. @@ -430,30 +429,54 @@ void can_cancel(CAN_Port* CANx, uint8 mbx) void can_rx_queue_clear(void) { nvic_irq_disable(NVIC_USB_LP_CAN_RX0); - can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + can_rx_head = can_rx_tail = can_rx_lost = 0; // JMD 2017/07/18 nvic_irq_enable(NVIC_USB_LP_CAN_RX0); + nvic_irq_enable(NVIC_CAN_RX1); } +// JMD 2017/07/18 -- changed uint8 can_rx_available(void) { - return can_rx_count; + if ( can_rx_head >= can_rx_tail ) + return can_rx_head - can_rx_tail ; + else + return CAN_RX_QUEUE_SIZE - ( can_rx_tail - can_rx_head ) ; +} + +// JMD 2017/07/18 -- added +uint8 can_frame_lost(void) +{ + if ( can_rx_lost != 0 ) + { + can_rx_lost = 0 ; + return 1 ; + } + return 0 ; + } CanMsg* can_rx_queue_get(void) { - if (can_rx_count == 0) + if (can_rx_head == can_rx_tail) // JMD 2017/07/18 -- changed return NULL; return &(can_rx_queue[can_rx_tail]); } + void can_rx_queue_free(void) { - if (can_rx_count > 0) + if (can_rx_head != can_rx_tail) // JMD 2017/07/18 -- changed { - nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // JMD problème d'atomicité + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // JMD atomicity problem + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective can_rx_tail = (can_rx_tail == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_tail + 1); - --can_rx_count; nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // fin JMD problème d'atomicité + nvic_irq_enable(NVIC_CAN_RX1); } } @@ -504,12 +527,11 @@ void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo) void can_rx_read(CAN_Port* CANx, CAN_FIFO fifo) { - if (can_rx_count < CAN_RX_QUEUE_SIZE) // read the message + if (can_rx_available() < CAN_RX_QUEUE_SIZE) // read the message { CanMsg* msg = &can_rx_queue[can_rx_head]; can_read(CANx, fifo, msg); can_rx_head = (can_rx_head == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_head + 1); - can_rx_count++; } else can_rx_lost = 1; // no place in queue, ignore package @@ -529,6 +551,12 @@ uint8 CAN_RX0_IRQ_Handler(void) return can_active; // return CAN active flag to USB handler } +// Addition JMD: the messages stored in fifo1 must also trigger an interrupt. +void __irq_can_rx1(void) +{ + CAN_RX0_IRQ_Handler() ; +} + void USB_HP_CAN_TX_IRQHandler (void) { if (can_active) diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.c.txt b/STM32F1/libraries/HardwareCAN/src/utility/can.c.txt new file mode 100644 index 000000000..64cedac5e --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.c.txt @@ -0,0 +1,591 @@ +//#include "libmaple.h" +#include "can.h" +//#include "rcc.h" +//#include "gpio.h" +//#include "nvic.h" +//#include "usb.h" + +/** + * CAN_interrupts + */ + +#define CAN_IT_RQCP0 ((uint32)0x00000005) /* Request completed mailbox 0 */ +#define CAN_IT_RQCP1 ((uint32)0x00000006) /* Request completed mailbox 1 */ +#define CAN_IT_RQCP2 ((uint32)0x00000007) /* Request completed mailbox 2 */ +#define CAN_IT_TME ((uint32)0x00000001) /* Transmit mailbox empty */ +#define CAN_IT_FMP0 ((uint32)0x00000002) /* FIFO 0 message pending */ +#define CAN_IT_FF0 ((uint32)0x00000004) /* FIFO 0 full */ +#define CAN_IT_FOV0 ((uint32)0x00000008) /* FIFO 0 overrun */ +#define CAN_IT_FMP1 ((uint32)0x00000010) /* FIFO 1 message pending */ +#define CAN_IT_FF1 ((uint32)0x00000020) /* FIFO 1 full */ +#define CAN_IT_FOV1 ((uint32)0x00000040) /* FIFO 1 overrun */ +#define CAN_IT_EWG ((uint32)0x00000100) /* Error warning */ +#define CAN_IT_EPV ((uint32)0x00000200) /* Error passive */ +#define CAN_IT_BOF ((uint32)0x00000400) /* Bus-off */ +#define CAN_IT_LEC ((uint32)0x00000800) /* Last error code */ +#define CAN_IT_ERR ((uint32)0x00008000) /* Error */ +#define CAN_IT_WKU ((uint32)0x00010000) /* Wake-up */ +#define CAN_IT_SLK ((uint32)0x00020000) /* Sleep */ + +/* Time out for INAK bit */ +#define CAN_INAK_TimeOut ((uint32)0x0000FFFF) + +/* Time out for SLAK bit */ +#define CAN_SLAK_TimeOut ((uint32)0x0000FFFF) + +#define CAN_CONTROL_MASK (CAN_MCR_TTCM | CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_NART | CAN_MCR_RFLM | CAN_MCR_TXFP) +#define CAN_TIMING_MASK (CAN_BTR_SJW | CAN_BTR_TS2 | CAN_BTR_TS1 | CAN_BTR_BRP) +#define CAN_MODE_MASK (CAN_BTR_LBKM | CAN_BTR_SILM) + +struct can_speed_info { + const uint32 btr; +}; + +#define CAN_CLOCK (36000000UL / 18UL) + +static const struct can_speed_info can_speed_table[] = { + [CAN_SPEED_125] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 125000UL - 1) + )}, + [CAN_SPEED_250] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 250000UL - 1) + )}, + [CAN_SPEED_500] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 500000UL - 1) + )}, + [CAN_SPEED_1000] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 1000000UL - 1) + )} +}; + +CAN_STATUS status; +CanMsg can_rx_queue[CAN_RX_QUEUE_SIZE]; + +// JMD 2017/07/18 -- added volatile to fix queue problems +volatile uint8 can_rx_head; +volatile uint8 can_rx_tail; +//volatile uint8 can_rx_count; // JMD 2017/07/18 -- redundant +volatile uint8 can_rx_lost; +uint8 can_active = 0; + +/** + * @brief Return last operation status + */ +CAN_STATUS can_status(void) +{ + return status; +} + +/** + * @brief Enter initialization mode + */ +CAN_STATUS can_init_enter(CAN_Port* CANx) +{ + volatile uint32 wait_ack = 0 ; + + status = CAN_OK; + if ((CANx->MSR & CAN_MSR_INAK) == 0) // Check for initialization mode already set + { + CANx->MCR |= CAN_MCR_INRQ; // Request initialisation + + wait_ack = 0; // Wait the acknowledge + while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) == 0)) + wait_ack++; + if ((CANx->MSR & CAN_MSR_INAK) == 0) + status = CAN_INIT_E_FAILED; // Timeout + } + return status; +} + +/** + * @brief Leave initialization mode + */ +CAN_STATUS can_init_leave(CAN_Port* CANx) +{ + volatile uint32 wait_ack = 0 ; + + status = CAN_OK; + if ((CANx->MSR & CAN_MSR_INAK) != 0) // Check for initialization mode already reset + { + CANx->MCR &= ~CAN_MCR_INRQ; // Clear Request initialization + + wait_ack = 0; // Wait the acknowledge + while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) != 0)) + wait_ack++; + if ((CANx->MSR & CAN_MSR_INAK) != 0) + status = CAN_INIT_L_FAILED; + } + return status; +} + +/** + * @brief Deinitializes the CAN peripheral registers to their default reset values. + */ +CAN_STATUS can_deinit(CAN_Port* CANx) +{ + if (CANx == CAN1_BASE) + { + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // Disable interrupts + nvic_irq_disable(NVIC_CAN_RX1); + nvic_irq_disable(NVIC_USB_HP_CAN_TX); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + rcc_reset_dev(RCC_CAN); + rcc_clk_disable(RCC_CAN); + can_active = 0; + } + return (status = CAN_OK); +} + +/** + * @brief Initialize CAN registers + */ +/* + * Bits in control parameter: + * CAN_MCR_TTCM time triggered communication mode + * CAN_MCR_ABOM automatic bus-off management + * CAN_MCR_AWUM automatic wake-up mode + * CAN_MCR_NART no automatic retransmission + * CAN_MCR_RFLM receive FIFO locked mode + * CAN_MCR_TXFP transmit FIFO priority + */ +CAN_STATUS can_init(CAN_Port* CANx, uint32 control, uint8 speed) +{ + status = CAN_INIT_FAILED; // default result status + // initialize receive message queue +// can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; // JMD 2017/07/18 + can_rx_head = can_rx_tail = can_rx_lost = 0; + + rcc_reset_dev(RCC_USB); //! X893 + rcc_clk_disable(RCC_USB); //! X893 +// line_dtr_rts = 0; //! X893 + rcc_clk_enable(RCC_AFIO); // enable clocks for AFIO + rcc_clk_enable(RCC_CAN); // and CAN + rcc_reset_dev(RCC_CAN); // reset CAN interface + + can_active = 1; // set CAN active flag (for interrupt handler + + CANx->MCR &= ~CAN_MCR_SLEEP; // reset CAN sleep mode (default after reset) + + if (can_init_enter(CANx) != CAN_OK) // enter CAN initialization mode + return status; // error, so return + + CANx->MCR &= ~CAN_CONTROL_MASK; // set mode bits + CANx->MCR |= (control & CAN_CONTROL_MASK); + + CANx->BTR &= ~CAN_TIMING_MASK; // Set the bit timing register + CANx->BTR |= (can_speed_table[speed].btr & CAN_TIMING_MASK); + + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // Enable interrupts + nvic_irq_enable(NVIC_CAN_RX1); + + nvic_irq_enable(NVIC_USB_HP_CAN_TX); + + CANx->IER = (CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | CAN_IER_TMEIE); + + if (can_init_leave(CANx) == CAN_OK) + { + while (!(CANx->TSR & CAN_TSR_TME0)); // Transmit mailbox 0 is empty + while (!(CANx->TSR & CAN_TSR_TME1)); // Transmit mailbox 0 is empty + while (!(CANx->TSR & CAN_TSR_TME2)); // Transmit mailbox 0 is empty + } + return status; +} + +/** + * @brief Set timing calues (CAN_BTR) + */ +CAN_STATUS can_set_timing(CAN_Port* CANx, uint32 timing) +{ + if (can_init_enter(CANx) == CAN_OK) + { + CANx->BTR = ((CANx->BTR & ~CAN_TIMING_MASK) | (timing & CAN_TIMING_MASK)); + can_init_leave(CANx); + } + return status; +} + +/** + * @brief Set CAN mode + * @param CANx pointer to CAN port + * @param mode CAN mode + */ +CAN_STATUS can_set_mode(CAN_Port* CANx, uint32 mode) +{ + if (can_init_enter(CANx) == CAN_OK) + { + CANx->BTR &= ~CAN_MODE_MASK; + CANx->BTR |= (mode & CAN_MODE_MASK); + can_init_leave(CANx); + } + return status; +} + +/** + * @brief Set CAN to GPIO mapping + */ +CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode) +{ + rcc_clk_enable(RCC_AFIO); + + status = CAN_INIT_FAILED; + if( CANx == CAN1_BASE) + { + switch(map_mode) + { + case CAN_GPIO_PB8_PB9: + rcc_clk_enable(RCC_GPIOB); + afio_remap(AFIO_MAPR_CAN_REMAP_PB8_PB9); + gpio_set_mode(GPIOB, 8, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOB, 9, GPIO_AF_OUTPUT_PP); + break; +#if NR_GPIO_PORTS >= 4 + case CAN_GPIO_PD0_PD1: + rcc_clk_enable(RCC_GPIOD); + afio_remap(AFIO_MAPR_CAN_REMAP_PD0_PD1); + gpio_set_mode(GPIOD, 0, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); + break; +#endif + default: + return status; + } + status = CAN_OK; + } + return status; +} + +CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2) +{ + uint32 mask = ((uint32)0x00000001) << filter_idx; + + CANx->FMR |= CAN_FMR_FINIT; // Initialization mode for the filter + CANx->FA1R &= ~mask; // Deactivation filter + + + if (scale == CAN_FILTER_32BIT) + CANx->FS1R |= mask; + else + CANx->FS1R &= ~mask; + + CANx->sFilterRegister[filter_idx].FR1 = fr1; + CANx->sFilterRegister[filter_idx].FR2 = fr2; + + if (mode == CAN_FILTER_MASK) + CANx->FM1R &= ~mask; + else + CANx->FM1R |= mask; + + if (fifo == CAN_FIFO0) + CANx->FFA1R &= ~mask; + else + CANx->FFA1R |= mask; + + CANx->FA1R |= mask; + CANx->FMR &= ~CAN_FMR_FINIT; + return CAN_OK; +} + + +/** + * @brief Initiates the transmission of a message. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param msg: pointer to a structure which contains CAN Id, CAN DLC and CAN datas. + * @retval : The number of the mailbox that is used for transmission or CAN_NO_MB if there is no empty mailbox. + */ +CAN_TX_MBX can_transmit(CAN_Port* CANx, CanMsg* msg) +{ + CAN_TX_MBX mbx; + uint32 data; + + /* Select one empty transmit mailbox */ + if (CANx->TSR & CAN_TSR_TME0) + mbx = CAN_TX_MBX0; + else if (CANx->TSR & CAN_TSR_TME1) + mbx = CAN_TX_MBX1; + else if (CANx->TSR & CAN_TSR_TME2) + mbx = CAN_TX_MBX2; + else + { + status = CAN_NO_MB; + return CAN_TX_NO_MBX; + } + + /* Set up the Id */ + if (msg->IDE == CAN_ID_STD) + data = (msg->ID << 21); + else + data = (msg->ID << 3) | CAN_ID_EXT; + + data |= ((uint32)msg->RTR); + + /* Set up the DLC */ + CANx->sTxMailBox[mbx].TDTR = (uint32)(msg->DLC & 0x0F); + + /* Set up the data field */ + CANx->sTxMailBox[mbx].TDLR = ( + ((uint32)msg->Data[3] << 24) | + ((uint32)msg->Data[2] << 16) | + ((uint32)msg->Data[1] << 8) | + ((uint32)msg->Data[0]) + ); + CANx->sTxMailBox[mbx].TDHR = ( + ((uint32)msg->Data[7] << 24) | + ((uint32)msg->Data[6] << 16) | + ((uint32)msg->Data[5] << 8) | + ((uint32)msg->Data[4]) + ); + /* Request transmission */ + CANx->sTxMailBox[mbx].TIR = (data | CAN_TMIDxR_TXRQ); + status = CAN_OK; + + return mbx; +} + +/** + * Checks the transmission of a message. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param mbx: the number of the mailbox that is used for transmission. + * @retval : CAN_TX_OK if the CAN driver transmits the message, CAN_TX_FAILED in an other case. + */ +CAN_STATUS can_tx_status(CAN_Port* CANx, CAN_TX_MBX mbx) +{ + /* RQCP, TXOK and TME bits */ + uint8 state = 0; + + switch (mbx) + { + case CAN_TX_MBX0: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP0) << 2); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK0) >> 0); + state |= (uint8)((CANx->TSR & CAN_TSR_TME0) >> 26); + break; + case CAN_TX_MBX1: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP1) >> 6); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK1) >> 8); + state |= (uint8)((CANx->TSR & CAN_TSR_TME1) >> 27); + break; + case CAN_TX_MBX2: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP2) >> 14); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK2) >> 16); + state |= (uint8)((CANx->TSR & CAN_TSR_TME2) >> 28); + break; + default: + status = CAN_TX_FAILED; + return status; + } + + // state = RQCP TXOK TME + switch (state) + { + /* transmit pending */ + case 0x0: + status = CAN_TX_PENDING; + break; + /* transmit failed */ + case 0x5: + status = CAN_TX_FAILED; + break; + /* transmit succedeed */ + case 0x7: + status = CAN_OK; + break; + default: + status = CAN_TX_FAILED; + break; + } + return status; +} + +/** + * @brief Cancels a transmit request. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param mbx: Mailbox number. + * @retval : None. + */ +void can_cancel(CAN_Port* CANx, uint8 mbx) +{ + /* abort transmission */ + switch (mbx) + { + case 0: + CANx->TSR |= CAN_TSR_ABRQ0; + break; + case 1: + CANx->TSR |= CAN_TSR_ABRQ1; + break; + case 2: + CANx->TSR |= CAN_TSR_ABRQ2; + break; + default: + break; + } +} + +void can_rx_queue_clear(void) +{ + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective +// can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; // JMD 2017/07/18 + can_rx_head = can_rx_tail = can_rx_lost = 0; // JMD 2017/07/18 + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); + nvic_irq_enable(NVIC_CAN_RX1); +} + +// JMD 2017/07/18 -- removed +/* +uint8 can_rx_available(void) +{ + return can_rx_count; +} +*/ + +// JMD 2017/07/18 -- added +uint8 can_rx_available(void) +{ + if ( can_rx_head >= can_rx_tail ) + return can_rx_head - can_rx_tail ; + else + return CAN_RX_QUEUE_SIZE - ( can_rx_tail - can_rx_head ) ; +} + +// JMD 2017/07/18 -- added +uint8 can_frame_lost(void) +{ + if ( can_rx_lost != 0 ) + { + can_rx_lost = 0 ; + return 1 ; + } + return 0 ; + +} + +CanMsg* can_rx_queue_get(void) +{ + if (can_rx_head == can_rx_tail) // JMD 2017/07/18 -- changed + return NULL; + return &(can_rx_queue[can_rx_tail]); +} + + +void can_rx_queue_free(void) +{ + if (can_rx_head != can_rx_tail) // JMD 2017/07/18 -- changed + { + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // JMD atomicity problem + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + can_rx_tail = (can_rx_tail == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_tail + 1); +// --can_rx_count; // JMD 2017/07/18 -- removed + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // fin JMD problème d'atomicité + nvic_irq_enable(NVIC_CAN_RX1); + } +} + +CanMsg* can_read(CAN_Port* CANx, CAN_FIFO fifo, CanMsg* msg) +{ + uint32 data = CANx->sFIFOMailBox[fifo].RIR; + + /* Get the Id */ + if (data & CAN_ID_EXT) + { + msg->ID = 0x1FFFFFFF & (data >> 3); + msg->IDE = (uint8)CAN_ID_EXT; + } + else + { + msg->ID = 0x000007FF & (data >> 21); + msg->IDE = (uint8)CAN_ID_STD; + } + + msg->RTR = (uint8)(CAN_RTR_REMOTE & data); + msg->DLC = (uint8)(0x0F & CANx->sFIFOMailBox[fifo].RDTR); + msg->FMI = (uint8)(0xFF & (CANx->sFIFOMailBox[fifo].RDTR >> 8)); + + /* Get the data field */ + data = CANx->sFIFOMailBox[fifo].RDLR; + uint8* p = msg->Data; + *p++ = (uint8)0xFF & data; + *p++ = (uint8)0xFF & (data >> 8); + *p++ = (uint8)0xFF & (data >> 16); + *p++ = (uint8)0xFF & (data >> 24); + + data = CANx->sFIFOMailBox[fifo].RDHR; + *p++ = (uint8)0xFF & data; + *p++ = (uint8)0xFF & (data >> 8); + *p++ = (uint8)0xFF & (data >> 16); + *p++ = (uint8)0xFF & (data >> 24); + + return msg; +} + +void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo) +{ + if (fifo == CAN_FIFO0) + CANx->RF0R |= (CAN_RF0R_RFOM0); // Release FIFO0 + else + CANx->RF1R |= (CAN_RF1R_RFOM1); // Release FIFO1 +} + +void can_rx_read(CAN_Port* CANx, CAN_FIFO fifo) +{ +// if (can_rx_count < CAN_RX_QUEUE_SIZE) // JMD 2017/07/18 + if (can_rx_available() < CAN_RX_QUEUE_SIZE) // read the message + { + CanMsg* msg = &can_rx_queue[can_rx_head]; + can_read(CANx, fifo, msg); + can_rx_head = (can_rx_head == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_head + 1); +// can_rx_count++; // JMD 2017/07/18 -- removed + } + else + can_rx_lost = 1; // no place in queue, ignore package + + can_rx_release(CANx, fifo); +} + +uint8 CAN_RX0_IRQ_Handler(void) +{ + if (can_active) + { + while ((CAN1_BASE->RF0R & CAN_RF0R_FMP0) != 0) + can_rx_read(CAN1_BASE, CAN_FIFO0); // message pending FIFO0 + while ((CAN1_BASE->RF1R & CAN_RF1R_FMP1) != 0) + can_rx_read(CAN1_BASE, CAN_FIFO1); // message pending FIFO1 + } + return can_active; // return CAN active flag to USB handler +} + +// Addition JMD: the messages stored in fifo1 must also trigger an interrupt. +void __irq_can_rx1(void) +{ + CAN_RX0_IRQ_Handler() ; +} + +void USB_HP_CAN_TX_IRQHandler (void) +{ + if (can_active) + { + if (CAN1_BASE->TSR & CAN_TSR_RQCP0) + CAN1_BASE->TSR |= CAN_TSR_RQCP0; // reset request complete mbx 0 + if (CAN1_BASE->TSR & CAN_TSR_RQCP1) + CAN1_BASE->TSR |= CAN_TSR_RQCP1; // reset request complete mbx 1 + if (CAN1_BASE->TSR & CAN_TSR_RQCP2) + CAN1_BASE->TSR |= CAN_TSR_RQCP2; // reset request complete mbx 2 + } +} diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.h b/STM32F1/libraries/HardwareCAN/src/utility/can.h index 576ac36fe..501390484 100644 --- a/STM32F1/libraries/HardwareCAN/src/utility/can.h +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.h @@ -285,6 +285,7 @@ CAN_STATUS can_status(void); void can_cancel(CAN_Port* CANx, uint8 mbx); void can_rx_queue_clear(void); uint8 can_rx_available(void); +uint8 can_frame_lost(void); CanMsg* can_rx_queue_get(void); CanMsg* can_read(CAN_Port* CANx, CAN_FIFO fifo, CanMsg* msg); void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo); diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.temp.c b/STM32F1/libraries/HardwareCAN/src/utility/can.temp.c new file mode 100644 index 000000000..e9b270c81 --- /dev/null +++ b/STM32F1/libraries/HardwareCAN/src/utility/can.temp.c @@ -0,0 +1,599 @@ +Skip to content +Features +Business +Explore +Marketplace +Pricing +This repository +Search +Sign in or Sign up + Watch 3 Star 2 Fork 363 megadrifter/Arduino_STM32 +forked from Phonog/Arduino_STM32 + Code Pull requests 0 Projects 0 Insights +Branch: megadrifter-GM… Find file Copy pathArduino_STM32/STM32F1/libraries/HardwareCAN/src/utility/can.c +a9807d2 9 days ago +@megadrifter megadrifter CAN filter corrected by tjb12345 +2 contributors @megadrifter @Phonog +RawBlameHistory +567 lines (500 sloc) 14.3 KB +#include "can.h" + +/** + * CAN_interrupts + */ + +#define CAN_IT_RQCP0 ((uint32)0x00000005) /* Request completed mailbox 0 */ +#define CAN_IT_RQCP1 ((uint32)0x00000006) /* Request completed mailbox 1 */ +#define CAN_IT_RQCP2 ((uint32)0x00000007) /* Request completed mailbox 2 */ +#define CAN_IT_TME ((uint32)0x00000001) /* Transmit mailbox empty */ +#define CAN_IT_FMP0 ((uint32)0x00000002) /* FIFO 0 message pending */ +#define CAN_IT_FF0 ((uint32)0x00000004) /* FIFO 0 full */ +#define CAN_IT_FOV0 ((uint32)0x00000008) /* FIFO 0 overrun */ +#define CAN_IT_FMP1 ((uint32)0x00000010) /* FIFO 1 message pending */ +#define CAN_IT_FF1 ((uint32)0x00000020) /* FIFO 1 full */ +#define CAN_IT_FOV1 ((uint32)0x00000040) /* FIFO 1 overrun */ +#define CAN_IT_EWG ((uint32)0x00000100) /* Error warning */ +#define CAN_IT_EPV ((uint32)0x00000200) /* Error passive */ +#define CAN_IT_BOF ((uint32)0x00000400) /* Bus-off */ +#define CAN_IT_LEC ((uint32)0x00000800) /* Last error code */ +#define CAN_IT_ERR ((uint32)0x00008000) /* Error */ +#define CAN_IT_WKU ((uint32)0x00010000) /* Wake-up */ +#define CAN_IT_SLK ((uint32)0x00020000) /* Sleep */ + +/* Time out for INAK bit */ +#define CAN_INAK_TimeOut ((uint32)0x0000FFFF) + +/* Time out for SLAK bit */ +#define CAN_SLAK_TimeOut ((uint32)0x0000FFFF) + +#define CAN_CONTROL_MASK (CAN_MCR_TTCM | CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_NART | CAN_MCR_RFLM | CAN_MCR_TXFP) +#define CAN_TIMING_MASK (CAN_BTR_SJW | CAN_BTR_TS2 | CAN_BTR_TS1 | CAN_BTR_BRP) +#define CAN_MODE_MASK (CAN_BTR_LBKM | CAN_BTR_SILM) + +struct can_speed_info { + const uint32 btr; +}; + +#define CAN_CLOCK (36000000UL / 18UL) + +static const struct can_speed_info can_speed_table[] = { + [CAN_SPEED_125] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 125000UL - 1) + )}, + [CAN_SPEED_250] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 250000UL - 1) + )}, + [CAN_SPEED_500] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 500000UL - 1) + )}, + [CAN_SPEED_1000] = { .btr = ( + (( 4-1) << CAN_BTR_SJW_POS) | + ((12-1) << CAN_BTR_TS1_POS) | + (( 5-1) << CAN_BTR_TS2_POS) | + (CAN_CLOCK / 1000000UL - 1) + )} +}; + +CAN_STATUS status; +CanMsg can_rx_queue[CAN_RX_QUEUE_SIZE]; + +// JMD 2017/07/18 -- added volatile to fix queue problems, removed can_rx_count +volatile uint8 can_rx_head; +volatile uint8 can_rx_tail; +volatile uint8 can_rx_lost; +uint8 can_active = 0; + +/** + * @brief Return last operation status + */ +CAN_STATUS can_status(void) +{ + return status; +} + +/** + * @brief Enter initialization mode + */ +CAN_STATUS can_init_enter(CAN_Port* CANx) +{ + volatile uint32 wait_ack = 0 ; + + status = CAN_OK; + if ((CANx->MSR & CAN_MSR_INAK) == 0) // Check for initialization mode already set + { + CANx->MCR |= CAN_MCR_INRQ; // Request initialisation + + wait_ack = 0; // Wait the acknowledge + while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) == 0)) + wait_ack++; + if ((CANx->MSR & CAN_MSR_INAK) == 0) + status = CAN_INIT_E_FAILED; // Timeout + } + return status; +} + +/** + * @brief Leave initialization mode + */ +CAN_STATUS can_init_leave(CAN_Port* CANx) +{ + volatile uint32 wait_ack = 0 ; + + status = CAN_OK; + if ((CANx->MSR & CAN_MSR_INAK) != 0) // Check for initialization mode already reset + { + CANx->MCR &= ~CAN_MCR_INRQ; // Clear Request initialization + + wait_ack = 0; // Wait the acknowledge + while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) != 0)) + wait_ack++; + if ((CANx->MSR & CAN_MSR_INAK) != 0) + status = CAN_INIT_L_FAILED; + } + return status; +} + +/** + * @brief Deinitializes the CAN peripheral registers to their default reset values. + */ +CAN_STATUS can_deinit(CAN_Port* CANx) +{ + if (CANx == CAN1_BASE) + { + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // Disable interrupts + nvic_irq_disable(NVIC_CAN_RX1); + nvic_irq_disable(NVIC_USB_HP_CAN_TX); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + rcc_reset_dev(RCC_CAN); + rcc_clk_disable(RCC_CAN); + can_active = 0; + } + return (status = CAN_OK); +} + +/** + * @brief Initialize CAN registers + */ +/* + * Bits in control parameter: + * CAN_MCR_TTCM time triggered communication mode + * CAN_MCR_ABOM automatic bus-off management + * CAN_MCR_AWUM automatic wake-up mode + * CAN_MCR_NART no automatic retransmission + * CAN_MCR_RFLM receive FIFO locked mode + * CAN_MCR_TXFP transmit FIFO priority + */ +CAN_STATUS can_init(CAN_Port* CANx, uint32 control, uint8 speed) +{ + status = CAN_INIT_FAILED; // default result status + // initialize receive message queue + can_rx_head = can_rx_tail = can_rx_lost = 0; + + rcc_reset_dev(RCC_USB); //! X893 + rcc_clk_disable(RCC_USB); //! X893 + rcc_clk_enable(RCC_AFIO); // enable clocks for AFIO + rcc_clk_enable(RCC_CAN); // and CAN + rcc_reset_dev(RCC_CAN); // reset CAN interface + + can_active = 1; // set CAN active flag (for interrupt handler + + CANx->MCR &= ~CAN_MCR_SLEEP; // reset CAN sleep mode (default after reset) + + if (can_init_enter(CANx) != CAN_OK) // enter CAN initialization mode + return status; // error, so return + + CANx->MCR &= ~CAN_CONTROL_MASK; // set mode bits + CANx->MCR |= (control & CAN_CONTROL_MASK); + + CANx->BTR &= ~CAN_TIMING_MASK; // Set the bit timing register + CANx->BTR |= (can_speed_table[speed].btr & CAN_TIMING_MASK); + + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // Enable interrupts + nvic_irq_enable(NVIC_CAN_RX1); + + nvic_irq_enable(NVIC_USB_HP_CAN_TX); + + CANx->IER = (CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | CAN_IER_TMEIE); + + if (can_init_leave(CANx) == CAN_OK) + { + while (!(CANx->TSR & CAN_TSR_TME0)); // Transmit mailbox 0 is empty + while (!(CANx->TSR & CAN_TSR_TME1)); // Transmit mailbox 0 is empty + while (!(CANx->TSR & CAN_TSR_TME2)); // Transmit mailbox 0 is empty + } + return status; +} + +/** + * @brief Set timing calues (CAN_BTR) + */ +CAN_STATUS can_set_timing(CAN_Port* CANx, uint32 timing) +{ + if (can_init_enter(CANx) == CAN_OK) + { + CANx->BTR = ((CANx->BTR & ~CAN_TIMING_MASK) | (timing & CAN_TIMING_MASK)); + can_init_leave(CANx); + } + return status; +} + +/** + * @brief Set CAN mode + * @param CANx pointer to CAN port + * @param mode CAN mode + */ +CAN_STATUS can_set_mode(CAN_Port* CANx, uint32 mode) +{ + if (can_init_enter(CANx) == CAN_OK) + { + CANx->BTR &= ~CAN_MODE_MASK; + CANx->BTR |= (mode & CAN_MODE_MASK); + can_init_leave(CANx); + } + return status; +} + +/** + * @brief Set CAN to GPIO mapping + */ +CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode) +{ + rcc_clk_enable(RCC_AFIO); + + status = CAN_INIT_FAILED; + if( CANx == CAN1_BASE) + { + switch(map_mode) + { + case CAN_GPIO_PB8_PB9: + rcc_clk_enable(RCC_GPIOB); + afio_remap(AFIO_MAPR_CAN_REMAP_PB8_PB9); + gpio_set_mode(GPIOB, 8, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOB, 9, GPIO_AF_OUTPUT_PP); + break; + case CAN_GPIO_PA11_PA12: + rcc_clk_enable(RCC_GPIOA); + afio_remap(AFIO_MAPR_CAN_REMAP_NONE); + gpio_set_mode(GPIOA, 11, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOA, 12, GPIO_AF_OUTPUT_PP); + break; +#if NR_GPIO_PORTS >= 4 + case CAN_GPIO_PD0_PD1: + rcc_clk_enable(RCC_GPIOD); + afio_remap(AFIO_MAPR_CAN_REMAP_PD0_PD1); + gpio_set_mode(GPIOD, 0, GPIO_INPUT_FLOATING); + gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); + break; +#endif + default: + return status; + } + status = CAN_OK; + } + return status; +} + +CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2, int extID = 0) +{ + uint32 mask = ((uint32)0x00000001) << filter_idx; + + CANx->FMR |= CAN_FMR_FINIT; // Initialization mode for the filter + CANx->FA1R &= ~mask; // Deactivation filter + + + if (scale == CAN_FILTER_32BIT) + CANx->FS1R |= mask; + else + CANx->FS1R &= ~mask; + if (extID) { + CANx->sFilterRegister[filter_idx].FR1 = (fr1 << 3) | CAN_ID_EXT; + CANx->sFilterRegister[filter_idx].FR2 = (fr2 << 3) | CAN_ID_EXT; + } + else { + CANx->sFilterRegister[filter_idx].FR1 = (fr1 << 21); + CANx->sFilterRegister[filter_idx].FR2 = (fr2 << 21); + } + if (mode == CAN_FILTER_MASK) + CANx->FM1R &= ~mask; + else + CANx->FM1R |= mask; + + if (fifo == CAN_FIFO0) + CANx->FFA1R &= ~mask; + else + CANx->FFA1R |= mask; + + CANx->FA1R |= mask; + CANx->FMR &= ~CAN_FMR_FINIT; + return CAN_OK; +} + + +/** + * @brief Initiates the transmission of a message. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param msg: pointer to a structure which contains CAN Id, CAN DLC and CAN datas. + * @retval : The number of the mailbox that is used for transmission or CAN_NO_MB if there is no empty mailbox. + */ +CAN_TX_MBX can_transmit(CAN_Port* CANx, CanMsg* msg) +{ + CAN_TX_MBX mbx; + uint32 data; + + /* Select one empty transmit mailbox */ + if (CANx->TSR & CAN_TSR_TME0) + mbx = CAN_TX_MBX0; + else if (CANx->TSR & CAN_TSR_TME1) + mbx = CAN_TX_MBX1; + else if (CANx->TSR & CAN_TSR_TME2) + mbx = CAN_TX_MBX2; + else + { + status = CAN_NO_MB; + return CAN_TX_NO_MBX; + } + + /* Set up the Id */ + if (msg->IDE == CAN_ID_STD) + data = (msg->ID << 21); + else + data = (msg->ID << 3) | CAN_ID_EXT; + + data |= ((uint32)msg->RTR); + + /* Set up the DLC */ + CANx->sTxMailBox[mbx].TDTR = (uint32)(msg->DLC & 0x0F); + + /* Set up the data field */ + CANx->sTxMailBox[mbx].TDLR = ( + ((uint32)msg->Data[3] << 24) | + ((uint32)msg->Data[2] << 16) | + ((uint32)msg->Data[1] << 8) | + ((uint32)msg->Data[0]) + ); + CANx->sTxMailBox[mbx].TDHR = ( + ((uint32)msg->Data[7] << 24) | + ((uint32)msg->Data[6] << 16) | + ((uint32)msg->Data[5] << 8) | + ((uint32)msg->Data[4]) + ); + /* Request transmission */ + CANx->sTxMailBox[mbx].TIR = (data | CAN_TMIDxR_TXRQ); + status = CAN_OK; + + return mbx; +} + +/** + * Checks the transmission of a message. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param mbx: the number of the mailbox that is used for transmission. + * @retval : CAN_TX_OK if the CAN driver transmits the message, CAN_TX_FAILED in an other case. + */ +CAN_STATUS can_tx_status(CAN_Port* CANx, CAN_TX_MBX mbx) +{ + /* RQCP, TXOK and TME bits */ + uint8 state = 0; + + switch (mbx) + { + case CAN_TX_MBX0: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP0) << 2); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK0) >> 0); + state |= (uint8)((CANx->TSR & CAN_TSR_TME0) >> 26); + break; + case CAN_TX_MBX1: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP1) >> 6); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK1) >> 8); + state |= (uint8)((CANx->TSR & CAN_TSR_TME1) >> 27); + break; + case CAN_TX_MBX2: + state |= (uint8)((CANx->TSR & CAN_TSR_RQCP2) >> 14); + state |= (uint8)((CANx->TSR & CAN_TSR_TXOK2) >> 16); + state |= (uint8)((CANx->TSR & CAN_TSR_TME2) >> 28); + break; + default: + status = CAN_TX_FAILED; + return status; + } + + // state = RQCP TXOK TME + switch (state) + { + /* transmit pending */ + case 0x0: + status = CAN_TX_PENDING; + break; + /* transmit failed */ + case 0x5: + status = CAN_TX_FAILED; + break; + /* transmit succedeed */ + case 0x7: + status = CAN_OK; + break; + default: + status = CAN_TX_FAILED; + break; + } + return status; +} + +/** + * @brief Cancels a transmit request. + * @param CANx: where x can be 1 to select the CAN peripheral. + * @param mbx: Mailbox number. + * @retval : None. + */ +void can_cancel(CAN_Port* CANx, uint8 mbx) +{ + /* abort transmission */ + switch (mbx) + { + case 0: + CANx->TSR |= CAN_TSR_ABRQ0; + break; + case 1: + CANx->TSR |= CAN_TSR_ABRQ1; + break; + case 2: + CANx->TSR |= CAN_TSR_ABRQ2; + break; + default: + break; + } +} + +void can_rx_queue_clear(void) +{ + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + can_rx_head = can_rx_tail = can_rx_lost = 0; // JMD 2017/07/18 + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); + nvic_irq_enable(NVIC_CAN_RX1); +} + +// JMD 2017/07/18 -- changed +uint8 can_rx_available(void) +{ + if ( can_rx_head >= can_rx_tail ) + return can_rx_head - can_rx_tail ; + else + return CAN_RX_QUEUE_SIZE - ( can_rx_tail - can_rx_head ) ; +} + +// JMD 2017/07/18 -- added +uint8 can_frame_lost(void) +{ + if ( can_rx_lost != 0 ) + { + can_rx_lost = 0 ; + return 1 ; + } + return 0 ; + +} + +CanMsg* can_rx_queue_get(void) +{ + if (can_rx_head == can_rx_tail) // JMD 2017/07/18 -- changed + return NULL; + return &(can_rx_queue[can_rx_tail]); +} + + +void can_rx_queue_free(void) +{ + if (can_rx_head != can_rx_tail) // JMD 2017/07/18 -- changed + { + nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // JMD atomicity problem + nvic_irq_disable(NVIC_CAN_RX1); + __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee + __asm volatile( "isb" ); // that the protection against interrupts is effective + can_rx_tail = (can_rx_tail == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_tail + 1); + nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // fin JMD problème d'atomicité + nvic_irq_enable(NVIC_CAN_RX1); + } +} + +CanMsg* can_read(CAN_Port* CANx, CAN_FIFO fifo, CanMsg* msg) +{ + uint32 data = CANx->sFIFOMailBox[fifo].RIR; + + /* Get the Id */ + if (data & CAN_ID_EXT) + { + msg->ID = 0x1FFFFFFF & (data >> 3); + msg->IDE = (uint8)CAN_ID_EXT; + } + else + { + msg->ID = 0x000007FF & (data >> 21); + msg->IDE = (uint8)CAN_ID_STD; + } + + msg->RTR = (uint8)(CAN_RTR_REMOTE & data); + msg->DLC = (uint8)(0x0F & CANx->sFIFOMailBox[fifo].RDTR); + msg->FMI = (uint8)(0xFF & (CANx->sFIFOMailBox[fifo].RDTR >> 8)); + + /* Get the data field */ + data = CANx->sFIFOMailBox[fifo].RDLR; + uint8* p = msg->Data; + *p++ = (uint8)0xFF & data; + *p++ = (uint8)0xFF & (data >> 8); + *p++ = (uint8)0xFF & (data >> 16); + *p++ = (uint8)0xFF & (data >> 24); + + data = CANx->sFIFOMailBox[fifo].RDHR; + *p++ = (uint8)0xFF & data; + *p++ = (uint8)0xFF & (data >> 8); + *p++ = (uint8)0xFF & (data >> 16); + *p++ = (uint8)0xFF & (data >> 24); + + return msg; +} + +void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo) +{ + if (fifo == CAN_FIFO0) + CANx->RF0R |= (CAN_RF0R_RFOM0); // Release FIFO0 + else + CANx->RF1R |= (CAN_RF1R_RFOM1); // Release FIFO1 +} + +void can_rx_read(CAN_Port* CANx, CAN_FIFO fifo) +{ + if (can_rx_available() < CAN_RX_QUEUE_SIZE) // read the message + { + CanMsg* msg = &can_rx_queue[can_rx_head]; + can_read(CANx, fifo, msg); + can_rx_head = (can_rx_head == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_head + 1); + } + else + can_rx_lost = 1; // no place in queue, ignore package + + can_rx_release(CANx, fifo); +} + +uint8 CAN_RX0_IRQ_Handler(void) +{ + if (can_active) + { + while ((CAN1_BASE->RF0R & CAN_RF0R_FMP0) != 0) + can_rx_read(CAN1_BASE, CAN_FIFO0); // message pending FIFO0 + while ((CAN1_BASE->RF1R & CAN_RF1R_FMP1) != 0) + can_rx_read(CAN1_BASE, CAN_FIFO1); // message pending FIFO1 + } + return can_active; // return CAN active flag to USB handler +} + +// Addition JMD: the messages stored in fifo1 must also trigger an interrupt. +void __irq_can_rx1(void) +{ + CAN_RX0_IRQ_Handler() ; +} + +void USB_HP_CAN_TX_IRQHandler (void) +{ + if (can_active) + { + if (CAN1_BASE->TSR & CAN_TSR_RQCP0) + CAN1_BASE->TSR |= CAN_TSR_RQCP0; // reset request complete mbx 0 + if (CAN1_BASE->TSR & CAN_TSR_RQCP1) + CAN1_BASE->TSR |= CAN_TSR_RQCP1; // reset request complete mbx 1 + if (CAN1_BASE->TSR & CAN_TSR_RQCP2) + CAN1_BASE->TSR |= CAN_TSR_RQCP2; // reset request complete mbx 2 + } +} From 3e43771540c61b8bf74e57554b0c990e1aa85950 Mon Sep 17 00:00:00 2001 From: megadrifter Date: Fri, 13 Oct 2017 14:11:25 +0300 Subject: [PATCH 17/18] latest files from Phonog --- STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp | 5 +++++ STM32F1/libraries/HardwareCAN/src/HardwareCAN.h | 1 + 2 files changed, 6 insertions(+) diff --git a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp index f113c4d85..a9b4071cc 100644 --- a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp +++ b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.cpp @@ -57,6 +57,11 @@ uint8 HardwareCAN::available(void) return can_rx_available(); } +uint8 HardwareCAN::frame_lost(void) +{ + return can_frame_lost() ; +} + CanMsg* HardwareCAN::recv(void) { return can_rx_queue_get(); diff --git a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.h b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.h index ccc318f5b..944187e14 100644 --- a/STM32F1/libraries/HardwareCAN/src/HardwareCAN.h +++ b/STM32F1/libraries/HardwareCAN/src/HardwareCAN.h @@ -54,6 +54,7 @@ class HardwareCAN void cancel(CAN_TX_MBX mbx); uint8 available(void); + uint8 frame_lost(void); CanMsg* recv(void); From d5ec148e83fdda70ddc6414485463a50c54fc9da Mon Sep 17 00:00:00 2001 From: Drift3r Date: Sat, 21 Apr 2018 11:50:25 +0300 Subject: [PATCH 18/18] delete unused files --- .../HardwareCAN/src/utility/can.c.txt | 591 ----------------- .../HardwareCAN/src/utility/can.temp.c | 599 ------------------ 2 files changed, 1190 deletions(-) delete mode 100644 STM32F1/libraries/HardwareCAN/src/utility/can.c.txt delete mode 100644 STM32F1/libraries/HardwareCAN/src/utility/can.temp.c diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.c.txt b/STM32F1/libraries/HardwareCAN/src/utility/can.c.txt deleted file mode 100644 index 64cedac5e..000000000 --- a/STM32F1/libraries/HardwareCAN/src/utility/can.c.txt +++ /dev/null @@ -1,591 +0,0 @@ -//#include "libmaple.h" -#include "can.h" -//#include "rcc.h" -//#include "gpio.h" -//#include "nvic.h" -//#include "usb.h" - -/** - * CAN_interrupts - */ - -#define CAN_IT_RQCP0 ((uint32)0x00000005) /* Request completed mailbox 0 */ -#define CAN_IT_RQCP1 ((uint32)0x00000006) /* Request completed mailbox 1 */ -#define CAN_IT_RQCP2 ((uint32)0x00000007) /* Request completed mailbox 2 */ -#define CAN_IT_TME ((uint32)0x00000001) /* Transmit mailbox empty */ -#define CAN_IT_FMP0 ((uint32)0x00000002) /* FIFO 0 message pending */ -#define CAN_IT_FF0 ((uint32)0x00000004) /* FIFO 0 full */ -#define CAN_IT_FOV0 ((uint32)0x00000008) /* FIFO 0 overrun */ -#define CAN_IT_FMP1 ((uint32)0x00000010) /* FIFO 1 message pending */ -#define CAN_IT_FF1 ((uint32)0x00000020) /* FIFO 1 full */ -#define CAN_IT_FOV1 ((uint32)0x00000040) /* FIFO 1 overrun */ -#define CAN_IT_EWG ((uint32)0x00000100) /* Error warning */ -#define CAN_IT_EPV ((uint32)0x00000200) /* Error passive */ -#define CAN_IT_BOF ((uint32)0x00000400) /* Bus-off */ -#define CAN_IT_LEC ((uint32)0x00000800) /* Last error code */ -#define CAN_IT_ERR ((uint32)0x00008000) /* Error */ -#define CAN_IT_WKU ((uint32)0x00010000) /* Wake-up */ -#define CAN_IT_SLK ((uint32)0x00020000) /* Sleep */ - -/* Time out for INAK bit */ -#define CAN_INAK_TimeOut ((uint32)0x0000FFFF) - -/* Time out for SLAK bit */ -#define CAN_SLAK_TimeOut ((uint32)0x0000FFFF) - -#define CAN_CONTROL_MASK (CAN_MCR_TTCM | CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_NART | CAN_MCR_RFLM | CAN_MCR_TXFP) -#define CAN_TIMING_MASK (CAN_BTR_SJW | CAN_BTR_TS2 | CAN_BTR_TS1 | CAN_BTR_BRP) -#define CAN_MODE_MASK (CAN_BTR_LBKM | CAN_BTR_SILM) - -struct can_speed_info { - const uint32 btr; -}; - -#define CAN_CLOCK (36000000UL / 18UL) - -static const struct can_speed_info can_speed_table[] = { - [CAN_SPEED_125] = { .btr = ( - (( 4-1) << CAN_BTR_SJW_POS) | - ((12-1) << CAN_BTR_TS1_POS) | - (( 5-1) << CAN_BTR_TS2_POS) | - (CAN_CLOCK / 125000UL - 1) - )}, - [CAN_SPEED_250] = { .btr = ( - (( 4-1) << CAN_BTR_SJW_POS) | - ((12-1) << CAN_BTR_TS1_POS) | - (( 5-1) << CAN_BTR_TS2_POS) | - (CAN_CLOCK / 250000UL - 1) - )}, - [CAN_SPEED_500] = { .btr = ( - (( 4-1) << CAN_BTR_SJW_POS) | - ((12-1) << CAN_BTR_TS1_POS) | - (( 5-1) << CAN_BTR_TS2_POS) | - (CAN_CLOCK / 500000UL - 1) - )}, - [CAN_SPEED_1000] = { .btr = ( - (( 4-1) << CAN_BTR_SJW_POS) | - ((12-1) << CAN_BTR_TS1_POS) | - (( 5-1) << CAN_BTR_TS2_POS) | - (CAN_CLOCK / 1000000UL - 1) - )} -}; - -CAN_STATUS status; -CanMsg can_rx_queue[CAN_RX_QUEUE_SIZE]; - -// JMD 2017/07/18 -- added volatile to fix queue problems -volatile uint8 can_rx_head; -volatile uint8 can_rx_tail; -//volatile uint8 can_rx_count; // JMD 2017/07/18 -- redundant -volatile uint8 can_rx_lost; -uint8 can_active = 0; - -/** - * @brief Return last operation status - */ -CAN_STATUS can_status(void) -{ - return status; -} - -/** - * @brief Enter initialization mode - */ -CAN_STATUS can_init_enter(CAN_Port* CANx) -{ - volatile uint32 wait_ack = 0 ; - - status = CAN_OK; - if ((CANx->MSR & CAN_MSR_INAK) == 0) // Check for initialization mode already set - { - CANx->MCR |= CAN_MCR_INRQ; // Request initialisation - - wait_ack = 0; // Wait the acknowledge - while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) == 0)) - wait_ack++; - if ((CANx->MSR & CAN_MSR_INAK) == 0) - status = CAN_INIT_E_FAILED; // Timeout - } - return status; -} - -/** - * @brief Leave initialization mode - */ -CAN_STATUS can_init_leave(CAN_Port* CANx) -{ - volatile uint32 wait_ack = 0 ; - - status = CAN_OK; - if ((CANx->MSR & CAN_MSR_INAK) != 0) // Check for initialization mode already reset - { - CANx->MCR &= ~CAN_MCR_INRQ; // Clear Request initialization - - wait_ack = 0; // Wait the acknowledge - while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) != 0)) - wait_ack++; - if ((CANx->MSR & CAN_MSR_INAK) != 0) - status = CAN_INIT_L_FAILED; - } - return status; -} - -/** - * @brief Deinitializes the CAN peripheral registers to their default reset values. - */ -CAN_STATUS can_deinit(CAN_Port* CANx) -{ - if (CANx == CAN1_BASE) - { - nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // Disable interrupts - nvic_irq_disable(NVIC_CAN_RX1); - nvic_irq_disable(NVIC_USB_HP_CAN_TX); - __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee - __asm volatile( "isb" ); // that the protection against interrupts is effective - rcc_reset_dev(RCC_CAN); - rcc_clk_disable(RCC_CAN); - can_active = 0; - } - return (status = CAN_OK); -} - -/** - * @brief Initialize CAN registers - */ -/* - * Bits in control parameter: - * CAN_MCR_TTCM time triggered communication mode - * CAN_MCR_ABOM automatic bus-off management - * CAN_MCR_AWUM automatic wake-up mode - * CAN_MCR_NART no automatic retransmission - * CAN_MCR_RFLM receive FIFO locked mode - * CAN_MCR_TXFP transmit FIFO priority - */ -CAN_STATUS can_init(CAN_Port* CANx, uint32 control, uint8 speed) -{ - status = CAN_INIT_FAILED; // default result status - // initialize receive message queue -// can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; // JMD 2017/07/18 - can_rx_head = can_rx_tail = can_rx_lost = 0; - - rcc_reset_dev(RCC_USB); //! X893 - rcc_clk_disable(RCC_USB); //! X893 -// line_dtr_rts = 0; //! X893 - rcc_clk_enable(RCC_AFIO); // enable clocks for AFIO - rcc_clk_enable(RCC_CAN); // and CAN - rcc_reset_dev(RCC_CAN); // reset CAN interface - - can_active = 1; // set CAN active flag (for interrupt handler - - CANx->MCR &= ~CAN_MCR_SLEEP; // reset CAN sleep mode (default after reset) - - if (can_init_enter(CANx) != CAN_OK) // enter CAN initialization mode - return status; // error, so return - - CANx->MCR &= ~CAN_CONTROL_MASK; // set mode bits - CANx->MCR |= (control & CAN_CONTROL_MASK); - - CANx->BTR &= ~CAN_TIMING_MASK; // Set the bit timing register - CANx->BTR |= (can_speed_table[speed].btr & CAN_TIMING_MASK); - - nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // Enable interrupts - nvic_irq_enable(NVIC_CAN_RX1); - - nvic_irq_enable(NVIC_USB_HP_CAN_TX); - - CANx->IER = (CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | CAN_IER_TMEIE); - - if (can_init_leave(CANx) == CAN_OK) - { - while (!(CANx->TSR & CAN_TSR_TME0)); // Transmit mailbox 0 is empty - while (!(CANx->TSR & CAN_TSR_TME1)); // Transmit mailbox 0 is empty - while (!(CANx->TSR & CAN_TSR_TME2)); // Transmit mailbox 0 is empty - } - return status; -} - -/** - * @brief Set timing calues (CAN_BTR) - */ -CAN_STATUS can_set_timing(CAN_Port* CANx, uint32 timing) -{ - if (can_init_enter(CANx) == CAN_OK) - { - CANx->BTR = ((CANx->BTR & ~CAN_TIMING_MASK) | (timing & CAN_TIMING_MASK)); - can_init_leave(CANx); - } - return status; -} - -/** - * @brief Set CAN mode - * @param CANx pointer to CAN port - * @param mode CAN mode - */ -CAN_STATUS can_set_mode(CAN_Port* CANx, uint32 mode) -{ - if (can_init_enter(CANx) == CAN_OK) - { - CANx->BTR &= ~CAN_MODE_MASK; - CANx->BTR |= (mode & CAN_MODE_MASK); - can_init_leave(CANx); - } - return status; -} - -/** - * @brief Set CAN to GPIO mapping - */ -CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode) -{ - rcc_clk_enable(RCC_AFIO); - - status = CAN_INIT_FAILED; - if( CANx == CAN1_BASE) - { - switch(map_mode) - { - case CAN_GPIO_PB8_PB9: - rcc_clk_enable(RCC_GPIOB); - afio_remap(AFIO_MAPR_CAN_REMAP_PB8_PB9); - gpio_set_mode(GPIOB, 8, GPIO_INPUT_FLOATING); - gpio_set_mode(GPIOB, 9, GPIO_AF_OUTPUT_PP); - break; -#if NR_GPIO_PORTS >= 4 - case CAN_GPIO_PD0_PD1: - rcc_clk_enable(RCC_GPIOD); - afio_remap(AFIO_MAPR_CAN_REMAP_PD0_PD1); - gpio_set_mode(GPIOD, 0, GPIO_INPUT_FLOATING); - gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); - break; -#endif - default: - return status; - } - status = CAN_OK; - } - return status; -} - -CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2) -{ - uint32 mask = ((uint32)0x00000001) << filter_idx; - - CANx->FMR |= CAN_FMR_FINIT; // Initialization mode for the filter - CANx->FA1R &= ~mask; // Deactivation filter - - - if (scale == CAN_FILTER_32BIT) - CANx->FS1R |= mask; - else - CANx->FS1R &= ~mask; - - CANx->sFilterRegister[filter_idx].FR1 = fr1; - CANx->sFilterRegister[filter_idx].FR2 = fr2; - - if (mode == CAN_FILTER_MASK) - CANx->FM1R &= ~mask; - else - CANx->FM1R |= mask; - - if (fifo == CAN_FIFO0) - CANx->FFA1R &= ~mask; - else - CANx->FFA1R |= mask; - - CANx->FA1R |= mask; - CANx->FMR &= ~CAN_FMR_FINIT; - return CAN_OK; -} - - -/** - * @brief Initiates the transmission of a message. - * @param CANx: where x can be 1 to select the CAN peripheral. - * @param msg: pointer to a structure which contains CAN Id, CAN DLC and CAN datas. - * @retval : The number of the mailbox that is used for transmission or CAN_NO_MB if there is no empty mailbox. - */ -CAN_TX_MBX can_transmit(CAN_Port* CANx, CanMsg* msg) -{ - CAN_TX_MBX mbx; - uint32 data; - - /* Select one empty transmit mailbox */ - if (CANx->TSR & CAN_TSR_TME0) - mbx = CAN_TX_MBX0; - else if (CANx->TSR & CAN_TSR_TME1) - mbx = CAN_TX_MBX1; - else if (CANx->TSR & CAN_TSR_TME2) - mbx = CAN_TX_MBX2; - else - { - status = CAN_NO_MB; - return CAN_TX_NO_MBX; - } - - /* Set up the Id */ - if (msg->IDE == CAN_ID_STD) - data = (msg->ID << 21); - else - data = (msg->ID << 3) | CAN_ID_EXT; - - data |= ((uint32)msg->RTR); - - /* Set up the DLC */ - CANx->sTxMailBox[mbx].TDTR = (uint32)(msg->DLC & 0x0F); - - /* Set up the data field */ - CANx->sTxMailBox[mbx].TDLR = ( - ((uint32)msg->Data[3] << 24) | - ((uint32)msg->Data[2] << 16) | - ((uint32)msg->Data[1] << 8) | - ((uint32)msg->Data[0]) - ); - CANx->sTxMailBox[mbx].TDHR = ( - ((uint32)msg->Data[7] << 24) | - ((uint32)msg->Data[6] << 16) | - ((uint32)msg->Data[5] << 8) | - ((uint32)msg->Data[4]) - ); - /* Request transmission */ - CANx->sTxMailBox[mbx].TIR = (data | CAN_TMIDxR_TXRQ); - status = CAN_OK; - - return mbx; -} - -/** - * Checks the transmission of a message. - * @param CANx: where x can be 1 to select the CAN peripheral. - * @param mbx: the number of the mailbox that is used for transmission. - * @retval : CAN_TX_OK if the CAN driver transmits the message, CAN_TX_FAILED in an other case. - */ -CAN_STATUS can_tx_status(CAN_Port* CANx, CAN_TX_MBX mbx) -{ - /* RQCP, TXOK and TME bits */ - uint8 state = 0; - - switch (mbx) - { - case CAN_TX_MBX0: - state |= (uint8)((CANx->TSR & CAN_TSR_RQCP0) << 2); - state |= (uint8)((CANx->TSR & CAN_TSR_TXOK0) >> 0); - state |= (uint8)((CANx->TSR & CAN_TSR_TME0) >> 26); - break; - case CAN_TX_MBX1: - state |= (uint8)((CANx->TSR & CAN_TSR_RQCP1) >> 6); - state |= (uint8)((CANx->TSR & CAN_TSR_TXOK1) >> 8); - state |= (uint8)((CANx->TSR & CAN_TSR_TME1) >> 27); - break; - case CAN_TX_MBX2: - state |= (uint8)((CANx->TSR & CAN_TSR_RQCP2) >> 14); - state |= (uint8)((CANx->TSR & CAN_TSR_TXOK2) >> 16); - state |= (uint8)((CANx->TSR & CAN_TSR_TME2) >> 28); - break; - default: - status = CAN_TX_FAILED; - return status; - } - - // state = RQCP TXOK TME - switch (state) - { - /* transmit pending */ - case 0x0: - status = CAN_TX_PENDING; - break; - /* transmit failed */ - case 0x5: - status = CAN_TX_FAILED; - break; - /* transmit succedeed */ - case 0x7: - status = CAN_OK; - break; - default: - status = CAN_TX_FAILED; - break; - } - return status; -} - -/** - * @brief Cancels a transmit request. - * @param CANx: where x can be 1 to select the CAN peripheral. - * @param mbx: Mailbox number. - * @retval : None. - */ -void can_cancel(CAN_Port* CANx, uint8 mbx) -{ - /* abort transmission */ - switch (mbx) - { - case 0: - CANx->TSR |= CAN_TSR_ABRQ0; - break; - case 1: - CANx->TSR |= CAN_TSR_ABRQ1; - break; - case 2: - CANx->TSR |= CAN_TSR_ABRQ2; - break; - default: - break; - } -} - -void can_rx_queue_clear(void) -{ - nvic_irq_disable(NVIC_USB_LP_CAN_RX0); - nvic_irq_disable(NVIC_CAN_RX1); - __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee - __asm volatile( "isb" ); // that the protection against interrupts is effective -// can_rx_head = can_rx_tail = can_rx_count = can_rx_lost = 0; // JMD 2017/07/18 - can_rx_head = can_rx_tail = can_rx_lost = 0; // JMD 2017/07/18 - nvic_irq_enable(NVIC_USB_LP_CAN_RX0); - nvic_irq_enable(NVIC_CAN_RX1); -} - -// JMD 2017/07/18 -- removed -/* -uint8 can_rx_available(void) -{ - return can_rx_count; -} -*/ - -// JMD 2017/07/18 -- added -uint8 can_rx_available(void) -{ - if ( can_rx_head >= can_rx_tail ) - return can_rx_head - can_rx_tail ; - else - return CAN_RX_QUEUE_SIZE - ( can_rx_tail - can_rx_head ) ; -} - -// JMD 2017/07/18 -- added -uint8 can_frame_lost(void) -{ - if ( can_rx_lost != 0 ) - { - can_rx_lost = 0 ; - return 1 ; - } - return 0 ; - -} - -CanMsg* can_rx_queue_get(void) -{ - if (can_rx_head == can_rx_tail) // JMD 2017/07/18 -- changed - return NULL; - return &(can_rx_queue[can_rx_tail]); -} - - -void can_rx_queue_free(void) -{ - if (can_rx_head != can_rx_tail) // JMD 2017/07/18 -- changed - { - nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // JMD atomicity problem - nvic_irq_disable(NVIC_CAN_RX1); - __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee - __asm volatile( "isb" ); // that the protection against interrupts is effective - can_rx_tail = (can_rx_tail == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_tail + 1); -// --can_rx_count; // JMD 2017/07/18 -- removed - nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // fin JMD problème d'atomicité - nvic_irq_enable(NVIC_CAN_RX1); - } -} - -CanMsg* can_read(CAN_Port* CANx, CAN_FIFO fifo, CanMsg* msg) -{ - uint32 data = CANx->sFIFOMailBox[fifo].RIR; - - /* Get the Id */ - if (data & CAN_ID_EXT) - { - msg->ID = 0x1FFFFFFF & (data >> 3); - msg->IDE = (uint8)CAN_ID_EXT; - } - else - { - msg->ID = 0x000007FF & (data >> 21); - msg->IDE = (uint8)CAN_ID_STD; - } - - msg->RTR = (uint8)(CAN_RTR_REMOTE & data); - msg->DLC = (uint8)(0x0F & CANx->sFIFOMailBox[fifo].RDTR); - msg->FMI = (uint8)(0xFF & (CANx->sFIFOMailBox[fifo].RDTR >> 8)); - - /* Get the data field */ - data = CANx->sFIFOMailBox[fifo].RDLR; - uint8* p = msg->Data; - *p++ = (uint8)0xFF & data; - *p++ = (uint8)0xFF & (data >> 8); - *p++ = (uint8)0xFF & (data >> 16); - *p++ = (uint8)0xFF & (data >> 24); - - data = CANx->sFIFOMailBox[fifo].RDHR; - *p++ = (uint8)0xFF & data; - *p++ = (uint8)0xFF & (data >> 8); - *p++ = (uint8)0xFF & (data >> 16); - *p++ = (uint8)0xFF & (data >> 24); - - return msg; -} - -void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo) -{ - if (fifo == CAN_FIFO0) - CANx->RF0R |= (CAN_RF0R_RFOM0); // Release FIFO0 - else - CANx->RF1R |= (CAN_RF1R_RFOM1); // Release FIFO1 -} - -void can_rx_read(CAN_Port* CANx, CAN_FIFO fifo) -{ -// if (can_rx_count < CAN_RX_QUEUE_SIZE) // JMD 2017/07/18 - if (can_rx_available() < CAN_RX_QUEUE_SIZE) // read the message - { - CanMsg* msg = &can_rx_queue[can_rx_head]; - can_read(CANx, fifo, msg); - can_rx_head = (can_rx_head == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_head + 1); -// can_rx_count++; // JMD 2017/07/18 -- removed - } - else - can_rx_lost = 1; // no place in queue, ignore package - - can_rx_release(CANx, fifo); -} - -uint8 CAN_RX0_IRQ_Handler(void) -{ - if (can_active) - { - while ((CAN1_BASE->RF0R & CAN_RF0R_FMP0) != 0) - can_rx_read(CAN1_BASE, CAN_FIFO0); // message pending FIFO0 - while ((CAN1_BASE->RF1R & CAN_RF1R_FMP1) != 0) - can_rx_read(CAN1_BASE, CAN_FIFO1); // message pending FIFO1 - } - return can_active; // return CAN active flag to USB handler -} - -// Addition JMD: the messages stored in fifo1 must also trigger an interrupt. -void __irq_can_rx1(void) -{ - CAN_RX0_IRQ_Handler() ; -} - -void USB_HP_CAN_TX_IRQHandler (void) -{ - if (can_active) - { - if (CAN1_BASE->TSR & CAN_TSR_RQCP0) - CAN1_BASE->TSR |= CAN_TSR_RQCP0; // reset request complete mbx 0 - if (CAN1_BASE->TSR & CAN_TSR_RQCP1) - CAN1_BASE->TSR |= CAN_TSR_RQCP1; // reset request complete mbx 1 - if (CAN1_BASE->TSR & CAN_TSR_RQCP2) - CAN1_BASE->TSR |= CAN_TSR_RQCP2; // reset request complete mbx 2 - } -} diff --git a/STM32F1/libraries/HardwareCAN/src/utility/can.temp.c b/STM32F1/libraries/HardwareCAN/src/utility/can.temp.c deleted file mode 100644 index e9b270c81..000000000 --- a/STM32F1/libraries/HardwareCAN/src/utility/can.temp.c +++ /dev/null @@ -1,599 +0,0 @@ -Skip to content -Features -Business -Explore -Marketplace -Pricing -This repository -Search -Sign in or Sign up - Watch 3 Star 2 Fork 363 megadrifter/Arduino_STM32 -forked from Phonog/Arduino_STM32 - Code Pull requests 0 Projects 0 Insights -Branch: megadrifter-GM… Find file Copy pathArduino_STM32/STM32F1/libraries/HardwareCAN/src/utility/can.c -a9807d2 9 days ago -@megadrifter megadrifter CAN filter corrected by tjb12345 -2 contributors @megadrifter @Phonog -RawBlameHistory -567 lines (500 sloc) 14.3 KB -#include "can.h" - -/** - * CAN_interrupts - */ - -#define CAN_IT_RQCP0 ((uint32)0x00000005) /* Request completed mailbox 0 */ -#define CAN_IT_RQCP1 ((uint32)0x00000006) /* Request completed mailbox 1 */ -#define CAN_IT_RQCP2 ((uint32)0x00000007) /* Request completed mailbox 2 */ -#define CAN_IT_TME ((uint32)0x00000001) /* Transmit mailbox empty */ -#define CAN_IT_FMP0 ((uint32)0x00000002) /* FIFO 0 message pending */ -#define CAN_IT_FF0 ((uint32)0x00000004) /* FIFO 0 full */ -#define CAN_IT_FOV0 ((uint32)0x00000008) /* FIFO 0 overrun */ -#define CAN_IT_FMP1 ((uint32)0x00000010) /* FIFO 1 message pending */ -#define CAN_IT_FF1 ((uint32)0x00000020) /* FIFO 1 full */ -#define CAN_IT_FOV1 ((uint32)0x00000040) /* FIFO 1 overrun */ -#define CAN_IT_EWG ((uint32)0x00000100) /* Error warning */ -#define CAN_IT_EPV ((uint32)0x00000200) /* Error passive */ -#define CAN_IT_BOF ((uint32)0x00000400) /* Bus-off */ -#define CAN_IT_LEC ((uint32)0x00000800) /* Last error code */ -#define CAN_IT_ERR ((uint32)0x00008000) /* Error */ -#define CAN_IT_WKU ((uint32)0x00010000) /* Wake-up */ -#define CAN_IT_SLK ((uint32)0x00020000) /* Sleep */ - -/* Time out for INAK bit */ -#define CAN_INAK_TimeOut ((uint32)0x0000FFFF) - -/* Time out for SLAK bit */ -#define CAN_SLAK_TimeOut ((uint32)0x0000FFFF) - -#define CAN_CONTROL_MASK (CAN_MCR_TTCM | CAN_MCR_ABOM | CAN_MCR_AWUM | CAN_MCR_NART | CAN_MCR_RFLM | CAN_MCR_TXFP) -#define CAN_TIMING_MASK (CAN_BTR_SJW | CAN_BTR_TS2 | CAN_BTR_TS1 | CAN_BTR_BRP) -#define CAN_MODE_MASK (CAN_BTR_LBKM | CAN_BTR_SILM) - -struct can_speed_info { - const uint32 btr; -}; - -#define CAN_CLOCK (36000000UL / 18UL) - -static const struct can_speed_info can_speed_table[] = { - [CAN_SPEED_125] = { .btr = ( - (( 4-1) << CAN_BTR_SJW_POS) | - ((12-1) << CAN_BTR_TS1_POS) | - (( 5-1) << CAN_BTR_TS2_POS) | - (CAN_CLOCK / 125000UL - 1) - )}, - [CAN_SPEED_250] = { .btr = ( - (( 4-1) << CAN_BTR_SJW_POS) | - ((12-1) << CAN_BTR_TS1_POS) | - (( 5-1) << CAN_BTR_TS2_POS) | - (CAN_CLOCK / 250000UL - 1) - )}, - [CAN_SPEED_500] = { .btr = ( - (( 4-1) << CAN_BTR_SJW_POS) | - ((12-1) << CAN_BTR_TS1_POS) | - (( 5-1) << CAN_BTR_TS2_POS) | - (CAN_CLOCK / 500000UL - 1) - )}, - [CAN_SPEED_1000] = { .btr = ( - (( 4-1) << CAN_BTR_SJW_POS) | - ((12-1) << CAN_BTR_TS1_POS) | - (( 5-1) << CAN_BTR_TS2_POS) | - (CAN_CLOCK / 1000000UL - 1) - )} -}; - -CAN_STATUS status; -CanMsg can_rx_queue[CAN_RX_QUEUE_SIZE]; - -// JMD 2017/07/18 -- added volatile to fix queue problems, removed can_rx_count -volatile uint8 can_rx_head; -volatile uint8 can_rx_tail; -volatile uint8 can_rx_lost; -uint8 can_active = 0; - -/** - * @brief Return last operation status - */ -CAN_STATUS can_status(void) -{ - return status; -} - -/** - * @brief Enter initialization mode - */ -CAN_STATUS can_init_enter(CAN_Port* CANx) -{ - volatile uint32 wait_ack = 0 ; - - status = CAN_OK; - if ((CANx->MSR & CAN_MSR_INAK) == 0) // Check for initialization mode already set - { - CANx->MCR |= CAN_MCR_INRQ; // Request initialisation - - wait_ack = 0; // Wait the acknowledge - while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) == 0)) - wait_ack++; - if ((CANx->MSR & CAN_MSR_INAK) == 0) - status = CAN_INIT_E_FAILED; // Timeout - } - return status; -} - -/** - * @brief Leave initialization mode - */ -CAN_STATUS can_init_leave(CAN_Port* CANx) -{ - volatile uint32 wait_ack = 0 ; - - status = CAN_OK; - if ((CANx->MSR & CAN_MSR_INAK) != 0) // Check for initialization mode already reset - { - CANx->MCR &= ~CAN_MCR_INRQ; // Clear Request initialization - - wait_ack = 0; // Wait the acknowledge - while ((wait_ack != CAN_INAK_TimeOut) && ((CANx->MSR & CAN_MSR_INAK) != 0)) - wait_ack++; - if ((CANx->MSR & CAN_MSR_INAK) != 0) - status = CAN_INIT_L_FAILED; - } - return status; -} - -/** - * @brief Deinitializes the CAN peripheral registers to their default reset values. - */ -CAN_STATUS can_deinit(CAN_Port* CANx) -{ - if (CANx == CAN1_BASE) - { - nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // Disable interrupts - nvic_irq_disable(NVIC_CAN_RX1); - nvic_irq_disable(NVIC_USB_HP_CAN_TX); - __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee - __asm volatile( "isb" ); // that the protection against interrupts is effective - rcc_reset_dev(RCC_CAN); - rcc_clk_disable(RCC_CAN); - can_active = 0; - } - return (status = CAN_OK); -} - -/** - * @brief Initialize CAN registers - */ -/* - * Bits in control parameter: - * CAN_MCR_TTCM time triggered communication mode - * CAN_MCR_ABOM automatic bus-off management - * CAN_MCR_AWUM automatic wake-up mode - * CAN_MCR_NART no automatic retransmission - * CAN_MCR_RFLM receive FIFO locked mode - * CAN_MCR_TXFP transmit FIFO priority - */ -CAN_STATUS can_init(CAN_Port* CANx, uint32 control, uint8 speed) -{ - status = CAN_INIT_FAILED; // default result status - // initialize receive message queue - can_rx_head = can_rx_tail = can_rx_lost = 0; - - rcc_reset_dev(RCC_USB); //! X893 - rcc_clk_disable(RCC_USB); //! X893 - rcc_clk_enable(RCC_AFIO); // enable clocks for AFIO - rcc_clk_enable(RCC_CAN); // and CAN - rcc_reset_dev(RCC_CAN); // reset CAN interface - - can_active = 1; // set CAN active flag (for interrupt handler - - CANx->MCR &= ~CAN_MCR_SLEEP; // reset CAN sleep mode (default after reset) - - if (can_init_enter(CANx) != CAN_OK) // enter CAN initialization mode - return status; // error, so return - - CANx->MCR &= ~CAN_CONTROL_MASK; // set mode bits - CANx->MCR |= (control & CAN_CONTROL_MASK); - - CANx->BTR &= ~CAN_TIMING_MASK; // Set the bit timing register - CANx->BTR |= (can_speed_table[speed].btr & CAN_TIMING_MASK); - - nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // Enable interrupts - nvic_irq_enable(NVIC_CAN_RX1); - - nvic_irq_enable(NVIC_USB_HP_CAN_TX); - - CANx->IER = (CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | CAN_IER_TMEIE); - - if (can_init_leave(CANx) == CAN_OK) - { - while (!(CANx->TSR & CAN_TSR_TME0)); // Transmit mailbox 0 is empty - while (!(CANx->TSR & CAN_TSR_TME1)); // Transmit mailbox 0 is empty - while (!(CANx->TSR & CAN_TSR_TME2)); // Transmit mailbox 0 is empty - } - return status; -} - -/** - * @brief Set timing calues (CAN_BTR) - */ -CAN_STATUS can_set_timing(CAN_Port* CANx, uint32 timing) -{ - if (can_init_enter(CANx) == CAN_OK) - { - CANx->BTR = ((CANx->BTR & ~CAN_TIMING_MASK) | (timing & CAN_TIMING_MASK)); - can_init_leave(CANx); - } - return status; -} - -/** - * @brief Set CAN mode - * @param CANx pointer to CAN port - * @param mode CAN mode - */ -CAN_STATUS can_set_mode(CAN_Port* CANx, uint32 mode) -{ - if (can_init_enter(CANx) == CAN_OK) - { - CANx->BTR &= ~CAN_MODE_MASK; - CANx->BTR |= (mode & CAN_MODE_MASK); - can_init_leave(CANx); - } - return status; -} - -/** - * @brief Set CAN to GPIO mapping - */ -CAN_STATUS can_gpio_map(CAN_Port* CANx, CAN_GPIO_MAP map_mode) -{ - rcc_clk_enable(RCC_AFIO); - - status = CAN_INIT_FAILED; - if( CANx == CAN1_BASE) - { - switch(map_mode) - { - case CAN_GPIO_PB8_PB9: - rcc_clk_enable(RCC_GPIOB); - afio_remap(AFIO_MAPR_CAN_REMAP_PB8_PB9); - gpio_set_mode(GPIOB, 8, GPIO_INPUT_FLOATING); - gpio_set_mode(GPIOB, 9, GPIO_AF_OUTPUT_PP); - break; - case CAN_GPIO_PA11_PA12: - rcc_clk_enable(RCC_GPIOA); - afio_remap(AFIO_MAPR_CAN_REMAP_NONE); - gpio_set_mode(GPIOA, 11, GPIO_INPUT_FLOATING); - gpio_set_mode(GPIOA, 12, GPIO_AF_OUTPUT_PP); - break; -#if NR_GPIO_PORTS >= 4 - case CAN_GPIO_PD0_PD1: - rcc_clk_enable(RCC_GPIOD); - afio_remap(AFIO_MAPR_CAN_REMAP_PD0_PD1); - gpio_set_mode(GPIOD, 0, GPIO_INPUT_FLOATING); - gpio_set_mode(GPIOD, 1, GPIO_AF_OUTPUT_PP); - break; -#endif - default: - return status; - } - status = CAN_OK; - } - return status; -} - -CAN_STATUS can_filter(CAN_Port* CANx, uint8 filter_idx, CAN_FIFO fifo, CAN_FILTER_SCALE scale, CAN_FILTER_MODE mode, uint32 fr1, uint32 fr2, int extID = 0) -{ - uint32 mask = ((uint32)0x00000001) << filter_idx; - - CANx->FMR |= CAN_FMR_FINIT; // Initialization mode for the filter - CANx->FA1R &= ~mask; // Deactivation filter - - - if (scale == CAN_FILTER_32BIT) - CANx->FS1R |= mask; - else - CANx->FS1R &= ~mask; - if (extID) { - CANx->sFilterRegister[filter_idx].FR1 = (fr1 << 3) | CAN_ID_EXT; - CANx->sFilterRegister[filter_idx].FR2 = (fr2 << 3) | CAN_ID_EXT; - } - else { - CANx->sFilterRegister[filter_idx].FR1 = (fr1 << 21); - CANx->sFilterRegister[filter_idx].FR2 = (fr2 << 21); - } - if (mode == CAN_FILTER_MASK) - CANx->FM1R &= ~mask; - else - CANx->FM1R |= mask; - - if (fifo == CAN_FIFO0) - CANx->FFA1R &= ~mask; - else - CANx->FFA1R |= mask; - - CANx->FA1R |= mask; - CANx->FMR &= ~CAN_FMR_FINIT; - return CAN_OK; -} - - -/** - * @brief Initiates the transmission of a message. - * @param CANx: where x can be 1 to select the CAN peripheral. - * @param msg: pointer to a structure which contains CAN Id, CAN DLC and CAN datas. - * @retval : The number of the mailbox that is used for transmission or CAN_NO_MB if there is no empty mailbox. - */ -CAN_TX_MBX can_transmit(CAN_Port* CANx, CanMsg* msg) -{ - CAN_TX_MBX mbx; - uint32 data; - - /* Select one empty transmit mailbox */ - if (CANx->TSR & CAN_TSR_TME0) - mbx = CAN_TX_MBX0; - else if (CANx->TSR & CAN_TSR_TME1) - mbx = CAN_TX_MBX1; - else if (CANx->TSR & CAN_TSR_TME2) - mbx = CAN_TX_MBX2; - else - { - status = CAN_NO_MB; - return CAN_TX_NO_MBX; - } - - /* Set up the Id */ - if (msg->IDE == CAN_ID_STD) - data = (msg->ID << 21); - else - data = (msg->ID << 3) | CAN_ID_EXT; - - data |= ((uint32)msg->RTR); - - /* Set up the DLC */ - CANx->sTxMailBox[mbx].TDTR = (uint32)(msg->DLC & 0x0F); - - /* Set up the data field */ - CANx->sTxMailBox[mbx].TDLR = ( - ((uint32)msg->Data[3] << 24) | - ((uint32)msg->Data[2] << 16) | - ((uint32)msg->Data[1] << 8) | - ((uint32)msg->Data[0]) - ); - CANx->sTxMailBox[mbx].TDHR = ( - ((uint32)msg->Data[7] << 24) | - ((uint32)msg->Data[6] << 16) | - ((uint32)msg->Data[5] << 8) | - ((uint32)msg->Data[4]) - ); - /* Request transmission */ - CANx->sTxMailBox[mbx].TIR = (data | CAN_TMIDxR_TXRQ); - status = CAN_OK; - - return mbx; -} - -/** - * Checks the transmission of a message. - * @param CANx: where x can be 1 to select the CAN peripheral. - * @param mbx: the number of the mailbox that is used for transmission. - * @retval : CAN_TX_OK if the CAN driver transmits the message, CAN_TX_FAILED in an other case. - */ -CAN_STATUS can_tx_status(CAN_Port* CANx, CAN_TX_MBX mbx) -{ - /* RQCP, TXOK and TME bits */ - uint8 state = 0; - - switch (mbx) - { - case CAN_TX_MBX0: - state |= (uint8)((CANx->TSR & CAN_TSR_RQCP0) << 2); - state |= (uint8)((CANx->TSR & CAN_TSR_TXOK0) >> 0); - state |= (uint8)((CANx->TSR & CAN_TSR_TME0) >> 26); - break; - case CAN_TX_MBX1: - state |= (uint8)((CANx->TSR & CAN_TSR_RQCP1) >> 6); - state |= (uint8)((CANx->TSR & CAN_TSR_TXOK1) >> 8); - state |= (uint8)((CANx->TSR & CAN_TSR_TME1) >> 27); - break; - case CAN_TX_MBX2: - state |= (uint8)((CANx->TSR & CAN_TSR_RQCP2) >> 14); - state |= (uint8)((CANx->TSR & CAN_TSR_TXOK2) >> 16); - state |= (uint8)((CANx->TSR & CAN_TSR_TME2) >> 28); - break; - default: - status = CAN_TX_FAILED; - return status; - } - - // state = RQCP TXOK TME - switch (state) - { - /* transmit pending */ - case 0x0: - status = CAN_TX_PENDING; - break; - /* transmit failed */ - case 0x5: - status = CAN_TX_FAILED; - break; - /* transmit succedeed */ - case 0x7: - status = CAN_OK; - break; - default: - status = CAN_TX_FAILED; - break; - } - return status; -} - -/** - * @brief Cancels a transmit request. - * @param CANx: where x can be 1 to select the CAN peripheral. - * @param mbx: Mailbox number. - * @retval : None. - */ -void can_cancel(CAN_Port* CANx, uint8 mbx) -{ - /* abort transmission */ - switch (mbx) - { - case 0: - CANx->TSR |= CAN_TSR_ABRQ0; - break; - case 1: - CANx->TSR |= CAN_TSR_ABRQ1; - break; - case 2: - CANx->TSR |= CAN_TSR_ABRQ2; - break; - default: - break; - } -} - -void can_rx_queue_clear(void) -{ - nvic_irq_disable(NVIC_USB_LP_CAN_RX0); - nvic_irq_disable(NVIC_CAN_RX1); - __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee - __asm volatile( "isb" ); // that the protection against interrupts is effective - can_rx_head = can_rx_tail = can_rx_lost = 0; // JMD 2017/07/18 - nvic_irq_enable(NVIC_USB_LP_CAN_RX0); - nvic_irq_enable(NVIC_CAN_RX1); -} - -// JMD 2017/07/18 -- changed -uint8 can_rx_available(void) -{ - if ( can_rx_head >= can_rx_tail ) - return can_rx_head - can_rx_tail ; - else - return CAN_RX_QUEUE_SIZE - ( can_rx_tail - can_rx_head ) ; -} - -// JMD 2017/07/18 -- added -uint8 can_frame_lost(void) -{ - if ( can_rx_lost != 0 ) - { - can_rx_lost = 0 ; - return 1 ; - } - return 0 ; - -} - -CanMsg* can_rx_queue_get(void) -{ - if (can_rx_head == can_rx_tail) // JMD 2017/07/18 -- changed - return NULL; - return &(can_rx_queue[can_rx_tail]); -} - - -void can_rx_queue_free(void) -{ - if (can_rx_head != can_rx_tail) // JMD 2017/07/18 -- changed - { - nvic_irq_disable(NVIC_USB_LP_CAN_RX0); // JMD atomicity problem - nvic_irq_disable(NVIC_CAN_RX1); - __asm volatile( "dsb" ); // Synchronization of the pipeline to guarantee - __asm volatile( "isb" ); // that the protection against interrupts is effective - can_rx_tail = (can_rx_tail == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_tail + 1); - nvic_irq_enable(NVIC_USB_LP_CAN_RX0); // fin JMD problème d'atomicité - nvic_irq_enable(NVIC_CAN_RX1); - } -} - -CanMsg* can_read(CAN_Port* CANx, CAN_FIFO fifo, CanMsg* msg) -{ - uint32 data = CANx->sFIFOMailBox[fifo].RIR; - - /* Get the Id */ - if (data & CAN_ID_EXT) - { - msg->ID = 0x1FFFFFFF & (data >> 3); - msg->IDE = (uint8)CAN_ID_EXT; - } - else - { - msg->ID = 0x000007FF & (data >> 21); - msg->IDE = (uint8)CAN_ID_STD; - } - - msg->RTR = (uint8)(CAN_RTR_REMOTE & data); - msg->DLC = (uint8)(0x0F & CANx->sFIFOMailBox[fifo].RDTR); - msg->FMI = (uint8)(0xFF & (CANx->sFIFOMailBox[fifo].RDTR >> 8)); - - /* Get the data field */ - data = CANx->sFIFOMailBox[fifo].RDLR; - uint8* p = msg->Data; - *p++ = (uint8)0xFF & data; - *p++ = (uint8)0xFF & (data >> 8); - *p++ = (uint8)0xFF & (data >> 16); - *p++ = (uint8)0xFF & (data >> 24); - - data = CANx->sFIFOMailBox[fifo].RDHR; - *p++ = (uint8)0xFF & data; - *p++ = (uint8)0xFF & (data >> 8); - *p++ = (uint8)0xFF & (data >> 16); - *p++ = (uint8)0xFF & (data >> 24); - - return msg; -} - -void can_rx_release(CAN_Port* CANx, CAN_FIFO fifo) -{ - if (fifo == CAN_FIFO0) - CANx->RF0R |= (CAN_RF0R_RFOM0); // Release FIFO0 - else - CANx->RF1R |= (CAN_RF1R_RFOM1); // Release FIFO1 -} - -void can_rx_read(CAN_Port* CANx, CAN_FIFO fifo) -{ - if (can_rx_available() < CAN_RX_QUEUE_SIZE) // read the message - { - CanMsg* msg = &can_rx_queue[can_rx_head]; - can_read(CANx, fifo, msg); - can_rx_head = (can_rx_head == (CAN_RX_QUEUE_SIZE - 1)) ? 0 : (can_rx_head + 1); - } - else - can_rx_lost = 1; // no place in queue, ignore package - - can_rx_release(CANx, fifo); -} - -uint8 CAN_RX0_IRQ_Handler(void) -{ - if (can_active) - { - while ((CAN1_BASE->RF0R & CAN_RF0R_FMP0) != 0) - can_rx_read(CAN1_BASE, CAN_FIFO0); // message pending FIFO0 - while ((CAN1_BASE->RF1R & CAN_RF1R_FMP1) != 0) - can_rx_read(CAN1_BASE, CAN_FIFO1); // message pending FIFO1 - } - return can_active; // return CAN active flag to USB handler -} - -// Addition JMD: the messages stored in fifo1 must also trigger an interrupt. -void __irq_can_rx1(void) -{ - CAN_RX0_IRQ_Handler() ; -} - -void USB_HP_CAN_TX_IRQHandler (void) -{ - if (can_active) - { - if (CAN1_BASE->TSR & CAN_TSR_RQCP0) - CAN1_BASE->TSR |= CAN_TSR_RQCP0; // reset request complete mbx 0 - if (CAN1_BASE->TSR & CAN_TSR_RQCP1) - CAN1_BASE->TSR |= CAN_TSR_RQCP1; // reset request complete mbx 1 - if (CAN1_BASE->TSR & CAN_TSR_RQCP2) - CAN1_BASE->TSR |= CAN_TSR_RQCP2; // reset request complete mbx 2 - } -}