Merge branch 'Phonog-patch-1' of https://github.com/Phonog/Arduino_STM32 into Phonog-Phonog-patch-1

This commit is contained in:
Roger Clark 2016-12-19 08:39:33 +11:00
commit 380b863292
14 changed files with 2570 additions and 0 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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=*

View File

@ -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;
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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

641
STM32F1/libraries/rcc.h Normal file
View File

@ -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 cant 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

174
STM32F1/libraries/rcc_f1.c Normal file
View File

@ -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);
}

402
STM32F1/libraries/usb.c Normal file
View File

@ -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();
}

View File

@ -439,6 +439,7 @@ typedef enum rcc_clk_id {
RCC_UART4,
RCC_UART5,
RCC_USB,
RCC_CAN, //! JMD after X893
} rcc_clk_id;
/**