diff --git a/STM32F1/cores/maple/libmaple/rcc_f1.c b/STM32F1/cores/maple/libmaple/rcc_f1.c index f45f670..9040a4d 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 diff --git a/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c b/STM32F1/cores/maple/libmaple/usb/stm32f1/usb.c index f837eb6..f796535 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) diff --git a/STM32F1/libraries/HardwareCAN/examples/HardwareCANexample/Changes.h b/STM32F1/libraries/HardwareCAN/examples/HardwareCANexample/Changes.h new file mode 100644 index 0000000..1ccd2fe --- /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 0000000..4e3a9e5 --- /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 0000000..6d901e3 --- /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 0000000..9186eb6 --- /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 0000000..f113c4d --- /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 0000000..ccc318f --- /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 0000000..0120e0e --- /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 0000000..576ac36 --- /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 0000000..aa9f8d3 --- /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 0000000..9040a4d --- /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 0000000..f796535 --- /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(); +} diff --git a/STM32F1/system/libmaple/stm32f1/include/series/rcc.h b/STM32F1/system/libmaple/stm32f1/include/series/rcc.h index f40dcba..aa9f8d3 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; /**