Merge branch 'Phonog-patch-1' of https://github.com/Phonog/Arduino_STM32 into Phonog-Phonog-patch-1
This commit is contained in:
commit
380b863292
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -0,0 +1,181 @@
|
|||
#include <HardwareCAN.h>
|
||||
#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)
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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=*
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,322 @@
|
|||
#ifndef _CAN_H_
|
||||
#define _CAN_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//#include "libmaple_types.h"
|
||||
#include <libmaple/libmaple_types.h>
|
||||
#include <libmaple/gpio.h>
|
||||
#include "libmaple/nvic.h"
|
||||
#include <libmaple/rcc.h>
|
||||
//#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
|
|
@ -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 <libmaple/libmaple_types.h>
|
||||
#include <libmaple/bitband.h>
|
||||
|
||||
/*
|
||||
* 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
|
|
@ -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 <libmaple/rcc.h>
|
||||
#include <libmaple/libmaple.h>
|
||||
#include <libmaple/bitband.h>
|
||||
|
||||
#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);
|
||||
}
|
|
@ -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 <libmaple/usb.h>
|
||||
|
||||
#include <libmaple/libmaple.h>
|
||||
#include <libmaple/rcc.h>
|
||||
|
||||
/* 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();
|
||||
}
|
|
@ -439,6 +439,7 @@ typedef enum rcc_clk_id {
|
|||
RCC_UART4,
|
||||
RCC_UART5,
|
||||
RCC_USB,
|
||||
RCC_CAN, //! JMD after X893
|
||||
} rcc_clk_id;
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue