forked from Imagelibrary/rtems
Add CAN, PWM, ADC and UART1/2/3 support to the LPC176x BSP.
This patch adds support for the following devices to the LPC176x BSP: * CAN * PWM * ADC It also adds the probe routines for UART1/2/3 to the console_device_table in console-config.c, and enables UART1 in configure.ac.
This commit is contained in:
committed by
Sebastian Huber
parent
6a941e3a99
commit
7b35a36fb1
@@ -42,6 +42,12 @@ include_bsp_HEADERS += include/io.h
|
||||
include_bsp_HEADERS += include/common-types.h
|
||||
include_bsp_HEADERS += include/gpio-defs.h
|
||||
include_bsp_HEADERS += include/gpio.h
|
||||
include_bsp_HEADERS += include/can.h
|
||||
include_bsp_HEADERS += include/can-defs.h
|
||||
include_bsp_HEADERS += include/pwmout.h
|
||||
include_bsp_HEADERS += include/pwmout-defs.h
|
||||
include_bsp_HEADERS += include/adc.h
|
||||
include_bsp_HEADERS += include/adc-defs.h
|
||||
include_bsp_HEADERS += include/timer-defs.h
|
||||
include_bsp_HEADERS += include/timer.h
|
||||
include_bsp_HEADERS += include/watchdog.h
|
||||
@@ -50,6 +56,7 @@ include_bsp_HEADERS += include/irq.h
|
||||
include_bsp_HEADERS += include/lpc176x.h
|
||||
include_bsp_HEADERS += include/lpc-clock-config.h
|
||||
include_bsp_HEADERS += include/system-clocks.h
|
||||
include_bsp_HEADERS += include/mbed-pinmap.h
|
||||
|
||||
include_HEADERS += ../../shared/include/tm27.h
|
||||
|
||||
@@ -126,6 +133,15 @@ libbsp_a_SOURCES += ../../shared/tod.c \
|
||||
# GPIO
|
||||
libbsp_a_SOURCES += gpio/gpio.c
|
||||
|
||||
# CAN
|
||||
libbsp_a_SOURCES += can/can.c
|
||||
|
||||
# PWMOUT
|
||||
libbsp_a_SOURCES += pwmout/pwmout.c
|
||||
|
||||
# ADC
|
||||
libbsp_a_SOURCES += adc/adc.c
|
||||
|
||||
# Timer
|
||||
libbsp_a_SOURCES += timer/timer.c
|
||||
|
||||
|
||||
244
c/src/lib/libbsp/arm/lpc176x/adc/adc.c
Executable file
244
c/src/lib/libbsp/arm/lpc176x/adc/adc.c
Executable file
@@ -0,0 +1,244 @@
|
||||
/**
|
||||
* @file adc.c
|
||||
*
|
||||
* @ingroup lpc176x
|
||||
*
|
||||
* @brief ADC library for the lpc176x bsp.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Taller Technologies.
|
||||
*
|
||||
* @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
#include <rtems/status-checks.h>
|
||||
#include <bsp/adc.h>
|
||||
#include <bsp/adc-defs.h>
|
||||
|
||||
static lpc176x_adc_device *const adc_device = AD0_BASE_ADDR;
|
||||
|
||||
static const lpc176x_adc_pin_map adc_pinmap[ ADC_DEVICES_COUNT ] =
|
||||
{
|
||||
{
|
||||
.pin_number = 23u,
|
||||
.pin_function = LPC176X_PIN_FUNCTION_01
|
||||
},
|
||||
{
|
||||
.pin_number = 24u,
|
||||
.pin_function = LPC176X_PIN_FUNCTION_01
|
||||
},
|
||||
{
|
||||
.pin_number = 25u,
|
||||
.pin_function = LPC176X_PIN_FUNCTION_01
|
||||
},
|
||||
{
|
||||
.pin_number = 26u,
|
||||
.pin_function = LPC176X_PIN_FUNCTION_01
|
||||
},
|
||||
{
|
||||
.pin_number = 62u,
|
||||
.pin_function = LPC176X_PIN_FUNCTION_11
|
||||
},
|
||||
{
|
||||
.pin_number = 63u,
|
||||
.pin_function = LPC176X_PIN_FUNCTION_11
|
||||
},
|
||||
{
|
||||
.pin_number = 3u,
|
||||
.pin_function = LPC176X_PIN_FUNCTION_10
|
||||
},
|
||||
{
|
||||
.pin_number = 2u,
|
||||
.pin_function = LPC176X_PIN_FUNCTION_10
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Checks for a valid pin number for an ADC
|
||||
*
|
||||
* @param pin_number The pin to check
|
||||
* @param adc_number The returned ADC device corresponding to that pin.
|
||||
*
|
||||
* @return true if valid, false otherwise.
|
||||
*/
|
||||
static bool valid_pin_number (
|
||||
const lpc176x_pin_number pin_number,
|
||||
lpc176x_adc_number *const adc_number
|
||||
)
|
||||
{
|
||||
bool found = false;
|
||||
lpc176x_adc_number adc_device = ADC_0;
|
||||
|
||||
while (!found && (adc_device < ADC_DEVICES_COUNT))
|
||||
{
|
||||
if (adc_pinmap[adc_device].pin_number == pin_number)
|
||||
{
|
||||
*adc_number = adc_device;
|
||||
found = true;
|
||||
}
|
||||
++adc_device;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Turns on the device and sets its clock divisor.
|
||||
*
|
||||
*/
|
||||
static void turn_on_and_set_clkdiv( void )
|
||||
{
|
||||
const uint32_t clkdiv = LPC176X_CCLK / ( LPC176X_PCLKDIV * MAX_ADC_CLK );
|
||||
|
||||
adc_device->ADCR = ADC_CR_PDN | ADC_CR_CLKDIV( clkdiv );
|
||||
}
|
||||
|
||||
rtems_status_code adc_open( const lpc176x_pin_number pin_number )
|
||||
{
|
||||
rtems_status_code sc = RTEMS_INVALID_NUMBER;
|
||||
lpc176x_adc_number adc_number = 0;
|
||||
if ( valid_pin_number( pin_number, &adc_number ) ) {
|
||||
sc =
|
||||
lpc176x_module_enable( LPC176X_MODULE_ADC, LPC176X_MODULE_PCLK_DEFAULT );
|
||||
RTEMS_CHECK_SC( sc, "enable adc module" );
|
||||
|
||||
turn_on_and_set_clkdiv();
|
||||
lpc176x_pin_select( adc_pinmap[ adc_number ].pin_number,
|
||||
adc_pinmap[ adc_number ].pin_function );
|
||||
lpc176x_pin_set_mode( adc_pinmap[ adc_number ].pin_number,
|
||||
LPC176X_PIN_MODE_NONE );
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
rtems_status_code adc_close( void )
|
||||
{
|
||||
adc_device->ADCR &= ~ADC_CR_PDN;
|
||||
|
||||
return lpc176x_module_disable( LPC176X_MODULE_ADC );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts the conversion for the given channel.
|
||||
*
|
||||
* @param number The channel to start the conversion.
|
||||
*/
|
||||
static inline void start_conversion( const lpc176x_adc_number number )
|
||||
{
|
||||
adc_device->ADCR =
|
||||
ADC_CR_SEL_SET( adc_device->ADCR, ( 1 << number ) ) | ADC_CR_START_NOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops the conversion.
|
||||
*
|
||||
*/
|
||||
static inline void stop_conversion( void )
|
||||
{
|
||||
adc_device->ADCR &= ~ADC_CR_START_NOW;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets float percentage of the result of a conversion.
|
||||
*
|
||||
* @param data The result of a conversion.
|
||||
* @return A float percentage (between 0.0f and 1.0f).
|
||||
*/
|
||||
static inline float get_float( const uint32_t data )
|
||||
{
|
||||
return ( (float) data / (float) ADC_RANGE );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Reads the ADC value for the given ADC number.
|
||||
*
|
||||
* @param adc_number Which ADC device read.
|
||||
* @return The read value.
|
||||
*/
|
||||
static uint32_t read( const lpc176x_adc_number adc_number )
|
||||
{
|
||||
uint32_t data;
|
||||
|
||||
start_conversion( adc_number );
|
||||
|
||||
do {
|
||||
data = adc_device->ADGDR;
|
||||
} while ( !ADC_DATA_CONVERSION_DONE( data ) );
|
||||
|
||||
stop_conversion();
|
||||
|
||||
return ADC_DR_VALUE( data );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the passed parameters are ordered from lowest
|
||||
* to highest.
|
||||
*
|
||||
* @param a The suggested lowest value.
|
||||
* @param b The suggested middle value.
|
||||
* @param c The suggested highest value.
|
||||
* @return True if it is in the right order, false otherwise.
|
||||
*/
|
||||
static inline bool lowest_to_highest_ordered(
|
||||
const uint32_t a,
|
||||
const uint32_t b,
|
||||
const uint32_t c
|
||||
)
|
||||
{
|
||||
return ( ( a <= b ) && ( b <= c ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets median value from the three passed parameters.
|
||||
*
|
||||
* @param a The first parameter.
|
||||
* @param b The second parameter.
|
||||
* @param c The third parameter.
|
||||
*
|
||||
* @return The median of the three parameters.
|
||||
*/
|
||||
static uint32_t get_median(
|
||||
const uint32_t a,
|
||||
const uint32_t b,
|
||||
const uint32_t c
|
||||
)
|
||||
{
|
||||
uint32_t median;
|
||||
|
||||
if ( lowest_to_highest_ordered( a, b, c)
|
||||
|| lowest_to_highest_ordered( c, b, a ) ) {
|
||||
median = b;
|
||||
} else if ( lowest_to_highest_ordered( b, a, c )
|
||||
|| lowest_to_highest_ordered( c, a, b ) ) {
|
||||
median = a;
|
||||
} else {
|
||||
median = c;
|
||||
}
|
||||
|
||||
return median;
|
||||
}
|
||||
|
||||
rtems_status_code adc_read(
|
||||
const lpc176x_pin_number pin_number ,
|
||||
float *const result
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_INVALID_NUMBER;
|
||||
lpc176x_adc_number adc_number = 0;
|
||||
if ( valid_pin_number( pin_number, &adc_number ) ) {
|
||||
const uint32_t first = read( adc_number );
|
||||
const uint32_t second = read( adc_number );
|
||||
const uint32_t third = read( adc_number );
|
||||
const uint32_t median = get_median( first, second, third );
|
||||
*result = get_float( median );
|
||||
sc = RTEMS_SUCCESSFUL;
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
542
c/src/lib/libbsp/arm/lpc176x/can/can.c
Executable file
542
c/src/lib/libbsp/arm/lpc176x/can/can.c
Executable file
@@ -0,0 +1,542 @@
|
||||
/**
|
||||
* @file can.c
|
||||
*
|
||||
* @ingroup lpc176x
|
||||
*
|
||||
* @brief CAN controller for the mbed lpc1768 board.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Taller Technologies.
|
||||
*
|
||||
* @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
|
||||
* @author Daniel Chicco (daniel.chicco@tallertechnologies.com)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems/status-checks.h>
|
||||
#include <bsp/irq.h>
|
||||
#include <bsp/can.h>
|
||||
#include <bsp/can-defs.h>
|
||||
#include <bsp/mbed-pinmap.h>
|
||||
|
||||
/**
|
||||
* @brief The standard isr to be installed for all the can devices.
|
||||
*
|
||||
* @param arg unused.
|
||||
*/
|
||||
static void can_isr( void *arg );
|
||||
|
||||
/**
|
||||
* @brief Vector of isr for the can_driver .
|
||||
*/
|
||||
lpc176x_can_isr_vector isr_vector;
|
||||
|
||||
/**
|
||||
* @brief Represents all the can devices, and useful things for initialization.
|
||||
*/
|
||||
static const can_driver_entry can_driver_table[ CAN_DEVICES_NUMBER ] =
|
||||
{
|
||||
{
|
||||
.device = (can_device *) CAN1_BASE_ADDR,
|
||||
.module = LPC176X_MODULE_CAN_0,
|
||||
.pconp_pin = LPC176X_SCB_PCONP_CAN_1,
|
||||
.pins = { DIP9, DIP10 },
|
||||
.pinfunction = LPC176X_PIN_FUNCTION_01
|
||||
},
|
||||
{
|
||||
.device = (can_device *) CAN2_BASE_ADDR,
|
||||
.module = LPC176X_MODULE_CAN_1,
|
||||
.pconp_pin = LPC176X_SCB_PCONP_CAN_2,
|
||||
.pins = { DIP30, DIP29 },
|
||||
.pinfunction = LPC176X_PIN_FUNCTION_10
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The CAN acceptance filter.
|
||||
*/
|
||||
can_acceptance_filter *const acceptance_filter_device =
|
||||
(can_acceptance_filter *) CAN_ACCEPT_BASE_ADDR;
|
||||
|
||||
/**
|
||||
* @brief Sets RX and TX pins for the passed can device number.
|
||||
*
|
||||
* @param cannumber CAN controller to be used.
|
||||
*/
|
||||
static inline void setpins( const lpc176x_can_number cannumber )
|
||||
{
|
||||
const can_driver_entry *const can_driver = &can_driver_table[ cannumber ];
|
||||
|
||||
lpc176x_pin_select( can_driver->pins[ CAN_TX_PIN ],
|
||||
can_driver->pinfunction );
|
||||
lpc176x_pin_select( can_driver->pins[ CAN_RX_PIN ],
|
||||
can_driver->pinfunction );
|
||||
}
|
||||
|
||||
rtems_status_code can_close( const lpc176x_can_number minor )
|
||||
{
|
||||
rtems_status_code sc = RTEMS_INVALID_NUMBER;
|
||||
|
||||
if ( CAN_DRIVER_IS_MINOR_VALID( minor ) ) {
|
||||
sc = RTEMS_SUCCESSFUL;
|
||||
const can_driver_entry *const can_driver = &can_driver_table[ minor ];
|
||||
lpc176x_module_disable( can_driver->module );
|
||||
}
|
||||
|
||||
/*else wrong parameters. return RTEMS_INVALID_NUMBER*/
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables CAN device.
|
||||
*
|
||||
* @param obj The device to be enabled.
|
||||
*/
|
||||
static inline void can_enable( const can_driver_entry *const obj )
|
||||
{
|
||||
if ( obj->device->MOD & CAN_MOD_RM ) {
|
||||
obj->device->MOD &= ~( CAN_MOD_RM );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables CAN device to set parameters, and returns the previous value
|
||||
* of the MOD register.
|
||||
*
|
||||
* @param obj The device to disable.
|
||||
* @return The previous status of MOD register.
|
||||
*/
|
||||
static inline uint32_t can_disable( const can_driver_entry *const obj )
|
||||
{
|
||||
const uint32_t sm = obj->device->MOD;
|
||||
|
||||
obj->device->MOD |= CAN_MOD_RM;
|
||||
|
||||
return sm;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Resets the error count.
|
||||
*
|
||||
* @param obj which device reset.
|
||||
*/
|
||||
static inline void can_reset( const can_driver_entry *const obj )
|
||||
{
|
||||
can_disable( obj );
|
||||
obj->device->GSR = 0; /* Reset error counter when CANxMOD is in reset*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This table has the sampling points as close to 75% as possible.
|
||||
* The first value is TSEG1, the second is TSEG2.
|
||||
*/
|
||||
static const unsigned int timing_pts[ MAX_TSEG1_TSEG2_BITS +
|
||||
1 ][ CAN_NUMBER_OF_TSEG ] = {
|
||||
{ 0x0, 0x0 }, /* 2, 50%*/
|
||||
{ 0x1, 0x0 }, /* 3, 67%*/
|
||||
{ 0x2, 0x0 }, /* 4, 75%*/
|
||||
{ 0x3, 0x0 }, /* 5, 80%*/
|
||||
{ 0x3, 0x1 }, /* 6, 67%*/
|
||||
{ 0x4, 0x1 }, /* 7, 71%*/
|
||||
{ 0x5, 0x1 }, /* 8, 75%*/
|
||||
{ 0x6, 0x1 }, /* 9, 78%*/
|
||||
{ 0x6, 0x2 }, /* 10, 70%*/
|
||||
{ 0x7, 0x2 }, /* 11, 73%*/
|
||||
{ 0x8, 0x2 }, /* 12, 75%*/
|
||||
{ 0x9, 0x2 }, /* 13, 77%*/
|
||||
{ 0x9, 0x3 }, /* 14, 71%*/
|
||||
{ 0xA, 0x3 }, /* 15, 73%*/
|
||||
{ 0xB, 0x3 }, /* 16, 75%*/
|
||||
{ 0xC, 0x3 }, /* 17, 76%*/
|
||||
{ 0xD, 0x3 }, /* 18, 78%*/
|
||||
{ 0xD, 0x4 }, /* 19, 74%*/
|
||||
{ 0xE, 0x4 }, /* 20, 75%*/
|
||||
{ 0xF, 0x4 }, /* 21, 76%*/
|
||||
{ 0xF, 0x5 }, /* 22, 73%*/
|
||||
{ 0xF, 0x6 }, /* 23, 70%*/
|
||||
{ 0xF, 0x7 }, /* 24, 67%*/
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Checks if divisor is a divisor of value.
|
||||
*
|
||||
* @param value The number to be divided.
|
||||
* @param divisor The divisor to check.
|
||||
*
|
||||
* @return true if "number" is divided by "divisor"; false otherwise.
|
||||
*/
|
||||
static inline bool is_divisor(
|
||||
const uint32_t value,
|
||||
const uint16_t divisor
|
||||
)
|
||||
{
|
||||
return ( ( value % divisor ) == 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the size of the two tseg values added according to the given
|
||||
* bitwidth and brp (The CAN prescaler).
|
||||
*
|
||||
* @param bitwidth The total bitwidth of a CAN bit (in pclk clocks).
|
||||
* @param brp The CAN clock prescaler.
|
||||
*
|
||||
* @return The value of tseg1 + tseg2 of the CAN bit. It is useful
|
||||
* to serve for index for timing_pts array).
|
||||
*/
|
||||
static inline uint32_t get_tseg_bit_size(
|
||||
const uint32_t bitwidth,
|
||||
const uint16_t brp
|
||||
)
|
||||
{
|
||||
return ( ( bitwidth / ( brp + CAN_BRP_EXTRA_BIT ) ) - CAN_TSEG_EXTRA_BITS );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets the brp and tsegbitsize in order to achieve the desired bitwidth.
|
||||
* @details The following must be fullfilled:
|
||||
*(brp + CAN_BRP_EXTRA_BIT) * (tsegbitsize + CAN_TSEG_EXTRA_BITS) == bitwidth
|
||||
*
|
||||
* @param bitwidth The bitwidth that we need to achieve.
|
||||
* @param brp Here it returns the calculated brp value.
|
||||
* @param tsegbitsize Here it returns the calculated tseg bit size value.
|
||||
* @return true if brp and tsegbitsize have been calculated.
|
||||
*/
|
||||
static inline bool get_brp_and_bitsize(
|
||||
const uint32_t bitwidth,
|
||||
uint16_t *const brp,
|
||||
uint32_t *const tsegbitsize
|
||||
)
|
||||
{
|
||||
bool hit = false;
|
||||
|
||||
while ( ( !hit ) && ( *brp < bitwidth / MIN_NUMBER_OF_CAN_BITS ) ) {
|
||||
if ( ( is_divisor( bitwidth, *brp + CAN_BRP_EXTRA_BIT ) )
|
||||
&& ( get_tseg_bit_size( bitwidth, *brp ) < MAX_TSEG1_TSEG2_BITS ) ) {
|
||||
hit = true;
|
||||
*tsegbitsize = get_tseg_bit_size( bitwidth, *brp );
|
||||
} else { /*Correct values not found, keep looking*/
|
||||
( *brp )++;
|
||||
}
|
||||
}
|
||||
|
||||
return hit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Constructs the btr register with the passed arguments.
|
||||
*
|
||||
* @param tsegbitsize The size tseg bits to set.
|
||||
* @param psjw The sjw to set.
|
||||
* @param brp The prescaler value to set.
|
||||
* @return The constructed btr register.
|
||||
*/
|
||||
static inline uint32_t get_btr(
|
||||
const uint32_t tsegbitsize,
|
||||
const unsigned char psjw,
|
||||
const uint32_t brp
|
||||
)
|
||||
{
|
||||
const uint32_t tseg2_value_masked =
|
||||
( ( timing_pts[ tsegbitsize ][ CAN_TSEG2 ] << CAN_BTR_TSEG2_SHIFT ) &
|
||||
CAN_BTR_TSEG2_MASK );
|
||||
const uint32_t tseg1_value_masked =
|
||||
( ( timing_pts[ tsegbitsize ][ CAN_TSEG1 ] <<
|
||||
CAN_BTR_TSEG1_SHIFT ) & CAN_BTR_TSEG1_MASK );
|
||||
const uint32_t psjw_value_masked =
|
||||
( ( psjw << CAN_BTR_SJW_SHIFT ) & CAN_BTR_SJW_MASK );
|
||||
const uint32_t brp_value_masked =
|
||||
( ( brp << CAN_BTR_BRP_SHIFT ) & CAN_BTR_BRP_MASK );
|
||||
|
||||
return tseg1_value_masked | tseg2_value_masked |
|
||||
psjw_value_masked | brp_value_masked;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calculates and returns a bit timing register (btr) for the desired
|
||||
* canclk frequency using the passed psjw, system clock and peripheral clock.
|
||||
*
|
||||
* @param systemclk The clock of the system (in Hz).
|
||||
* @param pclkdiv The peripheral clock divisor for the can device.
|
||||
* @param canclk The desired frequency for CAN (in Hz).
|
||||
* @param psjw The desired psjw.
|
||||
* @return The btr register value if found, WRONG_BTR_VALUE otherwise.
|
||||
*/
|
||||
static inline unsigned int can_speed(
|
||||
const unsigned int systemclk,
|
||||
const unsigned int pclkdiv,
|
||||
const unsigned int canclk,
|
||||
const unsigned char psjw
|
||||
)
|
||||
{
|
||||
uint32_t btr = WRONG_BTR_VALUE;
|
||||
const uint32_t bitwidth = systemclk / ( pclkdiv * canclk );
|
||||
|
||||
/* This is for the brp (prescaler) to start searching a reachable multiple.*/
|
||||
uint16_t brp = bitwidth / MAX_NUMBER_OF_CAN_BITS;
|
||||
uint32_t tsegbitsize;
|
||||
|
||||
if ( get_brp_and_bitsize( bitwidth, &brp, &tsegbitsize ) ) {
|
||||
btr = get_btr( tsegbitsize, psjw, brp );
|
||||
}
|
||||
|
||||
return btr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures the desired CAN device with the desired frequency.
|
||||
*
|
||||
* @param obj The can device to configure.
|
||||
* @param f The desired frequency.
|
||||
*
|
||||
* @return RTEMS_SUCCESSFUL if could be set, RTEMS_INVALID_NUMBER otherwise.
|
||||
*/
|
||||
static rtems_status_code can_frequency(
|
||||
const can_driver_entry *const obj,
|
||||
const can_freq freq
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_INVALID_NUMBER;
|
||||
const uint32_t btr = can_speed( LPC176X_CCLK, LPC176X_PCLKDIV, freq, 1 );
|
||||
|
||||
if ( btr != WRONG_BTR_VALUE ) {
|
||||
sc = RTEMS_SUCCESSFUL;
|
||||
uint32_t modmask = can_disable( obj );
|
||||
obj->device->BTR = btr;
|
||||
obj->device->MOD = modmask;
|
||||
} /*else couldnt found a good timing for the desired frequency,
|
||||
return RTEMS_INVALID_NUMBER.*/
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Installs the interrupt handler in rtems.
|
||||
*/
|
||||
static inline rtems_status_code can_initialize( void )
|
||||
{
|
||||
return rtems_interrupt_handler_install(
|
||||
LPC176X_IRQ_CAN,
|
||||
"can_interrupt",
|
||||
RTEMS_INTERRUPT_UNIQUE,
|
||||
can_isr,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
rtems_status_code can_open( const lpc176x_can_number minor, can_freq freq )
|
||||
{
|
||||
const can_driver_entry *const can_driver = &can_driver_table[ minor ];
|
||||
rtems_status_code sc = RTEMS_INVALID_NUMBER;
|
||||
|
||||
if ( CAN_DRIVER_IS_MINOR_VALID( minor ) ) {
|
||||
/*Enable CAN and acceptance filter modules.*/
|
||||
sc =
|
||||
lpc176x_module_enable( can_driver->module, LPC176X_MODULE_PCLK_DEFAULT );
|
||||
RTEMS_CHECK_SC( sc, "enable can module" );
|
||||
sc = lpc176x_module_enable( LPC176X_MODULE_ACCF,
|
||||
LPC176X_MODULE_PCLK_DEFAULT );
|
||||
RTEMS_CHECK_SC( sc, "enable acceptance filter" );
|
||||
/*Set pin functions.*/
|
||||
setpins( minor );
|
||||
|
||||
can_reset( can_driver );
|
||||
can_driver->device->IER = CAN_DEFAULT_INTERRUPT_CONFIGURATION;
|
||||
sc = can_frequency( can_driver, freq );
|
||||
RTEMS_CHECK_SC( sc, "Configure CAN frequency" );
|
||||
can_initialize();
|
||||
|
||||
acceptance_filter_device->AFMR = CAN_ACCF_AFMR_ACCBP; /*Bypass Filter.*/
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calls the installed isrs, according to the active interrupts.
|
||||
*
|
||||
* @param vector The read vector of active interrupts.
|
||||
* @param number The CAN device to look for interruptions.
|
||||
*/
|
||||
static inline void call_isrs(
|
||||
const uint32_t vector,
|
||||
const lpc176x_can_number number
|
||||
)
|
||||
{
|
||||
can_irq_type i;
|
||||
|
||||
for ( i = IRQ_RX; i < CAN_IRQ_NUMBER; ++i ) {
|
||||
if ( ( isr_vector[ i ] != NULL ) && ( vector & ( 1 << i ) ) )
|
||||
isr_vector[ i ]( number );
|
||||
|
||||
/* else this interrupt has not been raised or it hasn't got a handler,
|
||||
so do nothing.*/
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the passed CAN device is enabled and if it is checks for
|
||||
* active interrupts and calls its installed isr.
|
||||
*
|
||||
* @param number The CAN device to check for interrupts rised.
|
||||
*/
|
||||
static inline void search_and_call_int( const lpc176x_can_number number )
|
||||
{
|
||||
const can_driver_entry *const driver = &can_driver_table[ number ];
|
||||
|
||||
if ( LPC176X_SCB.pconp & driver->pconp_pin ) {
|
||||
/*We must read the whole register at once because it resets when read.*/
|
||||
const uint32_t int_vector = driver->device->ICR & CAN_INTERRUPT_TYPE_MASK;
|
||||
call_isrs( int_vector, number );
|
||||
}
|
||||
|
||||
/*else the device is shut down so we must do nothing.*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The standard isr to be installed for all the CAN devices.
|
||||
*
|
||||
* @param arg unused.
|
||||
*/
|
||||
static void can_isr( void *arg )
|
||||
{
|
||||
lpc176x_can_number i;
|
||||
|
||||
for ( i = CAN_0; i < CAN_DEVICES_NUMBER; ++i ) {
|
||||
search_and_call_int( i );
|
||||
}
|
||||
}
|
||||
|
||||
rtems_status_code can_read(
|
||||
const lpc176x_can_number minor,
|
||||
can_message *message
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_IO_ERROR;
|
||||
const can_driver_entry *const can_driver = &can_driver_table[ minor ];
|
||||
can_device *const dev = can_driver->device;
|
||||
registers_can_message *const msg = &( message->registers );
|
||||
|
||||
can_enable( can_driver );
|
||||
|
||||
if ( dev->GSR & CAN_GSR_RBS_MASK ) {
|
||||
sc = RTEMS_SUCCESSFUL;
|
||||
*msg = dev->receive;
|
||||
dev->CMR = CAN_CMR_RRB_MASK; /* release receive buffer. */
|
||||
} /* else Message not received.*/
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Array of masks and control bits for the transmit buffers.
|
||||
* It's used for each transmit buffer in order to see if it's available and to
|
||||
* send data to them.
|
||||
*/
|
||||
static const can_transmit_info transmit_info[ CAN_NUMBER_OF_TRANSMIT_BUFFERS ]
|
||||
=
|
||||
{
|
||||
{
|
||||
.can_status_mask = 0x00000004U,
|
||||
.not_cc_cmr_value = 0x21U
|
||||
},
|
||||
{
|
||||
.can_status_mask = 0x00000400U,
|
||||
.not_cc_cmr_value = 0x41U
|
||||
},
|
||||
{
|
||||
.can_status_mask = 0x00040000U,
|
||||
.not_cc_cmr_value = 0x81U
|
||||
}
|
||||
};
|
||||
|
||||
rtems_status_code can_write(
|
||||
const lpc176x_can_number minor,
|
||||
const can_message *const message
|
||||
)
|
||||
{
|
||||
const can_driver_entry *const can_driver = &can_driver_table[ minor ];
|
||||
can_device *const obj = can_driver->device;
|
||||
const uint32_t CANStatus = obj->SR;
|
||||
|
||||
const registers_can_message *const msg = &( message->registers );
|
||||
rtems_status_code sc = RTEMS_IO_ERROR;
|
||||
can_transmit_number transmit_buffer;
|
||||
|
||||
can_enable( can_driver );
|
||||
|
||||
for ( transmit_buffer = CAN_TRANSMIT1;
|
||||
( sc != RTEMS_SUCCESSFUL ) && ( transmit_buffer <
|
||||
CAN_NUMBER_OF_TRANSMIT_BUFFERS );
|
||||
++transmit_buffer ) {
|
||||
if ( CANStatus & transmit_info[ transmit_buffer ].can_status_mask ) {
|
||||
sc = RTEMS_SUCCESSFUL;
|
||||
obj->transmit[ transmit_buffer ] = *msg;
|
||||
obj->CMR = transmit_info[ transmit_buffer ].not_cc_cmr_value;
|
||||
} /*else can buffer busy, try with the next.*/
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Enables the interrupt type passed to the desired CAN device.
|
||||
*
|
||||
* @param number The CAN device to enable the interrupts.
|
||||
* @param type The type of interrupt to enable.
|
||||
*/
|
||||
static inline void can_enable_interrupt(
|
||||
const lpc176x_can_number number,
|
||||
const can_irq_type type
|
||||
)
|
||||
{
|
||||
const can_driver_entry *const driver = &can_driver_table[ number ];
|
||||
const uint32_t ier = 1 << type;
|
||||
|
||||
can_disable( driver );
|
||||
driver->device->IER |= ier;
|
||||
can_enable( driver );
|
||||
}
|
||||
|
||||
rtems_status_code can_register_isr(
|
||||
const lpc176x_can_number number,
|
||||
const can_irq_type type,
|
||||
const lpc176x_can_isr isr
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_INVALID_NUMBER;
|
||||
|
||||
if ( ( 0 <= type ) && ( type < CAN_IRQ_NUMBER ) ) {
|
||||
sc = RTEMS_SUCCESSFUL;
|
||||
isr_vector[ type ] = isr;
|
||||
can_enable_interrupt( number, type );
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
rtems_status_code create_can_message(
|
||||
can_message *const msg,
|
||||
const int _id,
|
||||
const char *const _data,
|
||||
const char _len
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_INVALID_NUMBER;
|
||||
|
||||
if ( ( _len <= CAN_MAXIMUM_DATA_SIZE ) && ( _id <= CAN10_MAXIMUM_ID ) ) {
|
||||
sc = RTEMS_SUCCESSFUL;
|
||||
msg->low_level.dlc = _len;
|
||||
msg->low_level.type = CANStandard;
|
||||
msg->low_level.rtr = CANData;
|
||||
msg->low_level.id = _id;
|
||||
memcpy( msg->low_level.data, _data, _len );
|
||||
}
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
@@ -49,6 +49,9 @@ RTEMS_BSPOPTS_HELP([LPC176X_PCLKDIV],[clock divider for default
|
||||
RTEMS_BSPOPTS_SET([LPC176X_UART_BAUD],[*],[9600U])
|
||||
RTEMS_BSPOPTS_HELP([LPC176X_UART_BAUD],[baud for UARTs])
|
||||
|
||||
RTEMS_BSPOPTS_SET([LPC176X_CONFIG_UART_1],[*],[1])
|
||||
RTEMS_BSPOPTS_HELP([LPC176X_CONFIG_UART_1],[Use Uart 1])
|
||||
|
||||
RTEMS_BSPOPTS_SET([LPC176X_CONFIG_CONSOLE],[*],[0])
|
||||
RTEMS_BSPOPTS_HELP([LPC176X_CONFIG_CONSOLE],[configuration
|
||||
for console (UART 0)])
|
||||
|
||||
@@ -62,6 +62,42 @@ static inline void lpc176x_uart_set_register(
|
||||
reg[ i ] = val;
|
||||
}
|
||||
|
||||
static bool lpc176x_uart1_probe(rtems_termios_device_context *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
|
||||
lpc176x_module_enable( LPC176X_MODULE_UART_1, LPC176X_MODULE_PCLK_DEFAULT );
|
||||
|
||||
lpc176x_pin_select( LPC176X_PIN_UART_1_TXD, LPC176X_PIN_FUNCTION_01 );
|
||||
lpc176x_pin_select( LPC176X_PIN_UART_1_RXD, LPC176X_PIN_FUNCTION_01 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool lpc176x_uart2_probe(rtems_termios_device_context *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
|
||||
lpc176x_module_enable( LPC176X_MODULE_UART_2, LPC176X_MODULE_PCLK_DEFAULT );
|
||||
|
||||
lpc176x_pin_select( LPC176X_PIN_UART_2_TXD, LPC176X_PIN_FUNCTION_01 );
|
||||
lpc176x_pin_select( LPC176X_PIN_UART_2_RXD, LPC176X_PIN_FUNCTION_01 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool lpc176x_uart3_probe(rtems_termios_device_context *ctx)
|
||||
{
|
||||
(void)ctx;
|
||||
|
||||
lpc176x_module_enable( LPC176X_MODULE_UART_3, LPC176X_MODULE_PCLK_DEFAULT );
|
||||
|
||||
lpc176x_pin_select( LPC176X_PIN_UART_3_TXD, LPC176X_PIN_FUNCTION_10 );
|
||||
lpc176x_pin_select( LPC176X_PIN_UART_3_RXD, LPC176X_PIN_FUNCTION_10 );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef LPC176X_CONFIG_CONSOLE
|
||||
static ns16550_context lpc176x_uart_context_0 = {
|
||||
.base = RTEMS_TERMIOS_DEVICE_CONTEXT_INITIALIZER("UART 0"),
|
||||
@@ -126,7 +162,7 @@ const console_device console_device_table[] = {
|
||||
#ifdef LPC176X_CONFIG_UART_1
|
||||
{
|
||||
.device_file = "/dev/ttyS1",
|
||||
.probe = ns16550_probe,
|
||||
.probe = lpc176x_uart1_probe,
|
||||
.handler = &ns16550_handler_interrupt,
|
||||
.context = &lpc176x_uart_context_1.base
|
||||
},
|
||||
@@ -134,7 +170,7 @@ const console_device console_device_table[] = {
|
||||
#ifdef LPC176X_CONFIG_UART_2
|
||||
{
|
||||
.device_file = "/dev/ttyS2",
|
||||
.probe = ns16550_probe,
|
||||
.probe = lpc176x_uart2_probe,
|
||||
.handler = &ns16550_handler_interrupt,
|
||||
.context = &lpc176x_uart_context_2.base
|
||||
},
|
||||
@@ -142,7 +178,7 @@ const console_device console_device_table[] = {
|
||||
#ifdef LPC176X_CONFIG_UART_3
|
||||
{
|
||||
.device_file = "/dev/ttyS3",
|
||||
.probe = ns16550_probe,
|
||||
.probe = lpc176x_uart3_probe,
|
||||
.handler = &ns16550_handler_interrupt,
|
||||
.context = &lpc176x_uart_context_3.base
|
||||
},
|
||||
|
||||
96
c/src/lib/libbsp/arm/lpc176x/include/adc-defs.h
Executable file
96
c/src/lib/libbsp/arm/lpc176x/include/adc-defs.h
Executable file
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* @file adc-defs.h
|
||||
*
|
||||
* @ingroup lpc176x
|
||||
*
|
||||
* @brief ADC library for the lpc176x bsp.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Taller Technologies.
|
||||
*
|
||||
* @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
#ifndef LPC176X_ADC_DEFS_H
|
||||
#define LPC176X_ADC_DEFS_H
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/io.h>
|
||||
#include <bsp/lpc176x.h>
|
||||
#include <bsp/adc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @brief The ADC inputs of the board.
|
||||
*/
|
||||
typedef enum {
|
||||
ADC_0,
|
||||
ADC_1,
|
||||
ADC_2,
|
||||
ADC_3,
|
||||
ADC_4,
|
||||
ADC_5,
|
||||
ADC_6,
|
||||
ADC_7,
|
||||
ADC_DEVICES_COUNT
|
||||
} lpc176x_adc_number;
|
||||
|
||||
#define MAX_ADC_CLK 13000000u
|
||||
|
||||
#define ADC_RANGE 0xFFFu
|
||||
|
||||
#define ADC_NUMBER_VALID( number ) ( ( (uint32_t) number ) < \
|
||||
ADC_DEVICES_COUNT )
|
||||
|
||||
#define ADC_CR_SEL( val ) BSP_FLD32( val, 0, 7 )
|
||||
#define ADC_CR_SEL_GET( val ) BSP_FLD32GET( val, 0, 7 )
|
||||
#define ADC_CR_SEL_SET( reg, val ) BSP_FLD32SET( reg, val, 0, 7 )
|
||||
#define ADC_CR_CLKDIV( val ) BSP_FLD32( val, 8, 15 )
|
||||
#define ADC_CR_CLKDIV_GET( reg ) BSP_FLD32GET( reg, 8, 15 )
|
||||
#define ADC_CR_CLKDIV_SET( reg, val ) BSP_FLD32SET( reg, val, 8, 15 )
|
||||
#define ADC_CR_BURST BSP_BIT32( 16 )
|
||||
#define ADC_CR_CLKS( val ) BSP_FLD32( val, 17, 19 )
|
||||
#define ADC_CR_PDN BSP_BIT32( 21 )
|
||||
#define ADC_CR_START_NOW BSP_BIT32( 24 )
|
||||
#define ADC_CR_START( val ) BSP_FLD32( val, 24, 26 )
|
||||
#define ADC_CR_EDGE BSP_BIT32( 27 )
|
||||
|
||||
#define ADC_DR_VALUE( reg ) BSP_FLD32GET( reg, 4, 15 )
|
||||
#define ADC_DR_OVERRUN BSP_BIT32( 30 )
|
||||
#define ADC_DR_DONE BSP_BIT32( 31 )
|
||||
|
||||
#define ADC_DATA_CONVERSION_DONE( val ) ( ( val & ADC_DR_DONE ) != 0u )
|
||||
|
||||
/**
|
||||
* @brief The ADC low-level device.
|
||||
*/
|
||||
typedef struct {
|
||||
volatile uint32_t ADCR;
|
||||
volatile uint32_t ADGDR;
|
||||
volatile uint32_t RESERVED0;
|
||||
volatile uint32_t ADINTEN;
|
||||
volatile uint32_t ADDR[ ADC_DEVICES_COUNT ];
|
||||
volatile uint32_t ADSTAT;
|
||||
volatile uint32_t ADTRM;
|
||||
} lpc176x_adc_device;
|
||||
|
||||
/**
|
||||
* @brief Represents the pin and function for each ADC input.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t pin_number;
|
||||
lpc176x_pin_function pin_function;
|
||||
} lpc176x_adc_pin_map;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
60
c/src/lib/libbsp/arm/lpc176x/include/adc.h
Executable file
60
c/src/lib/libbsp/arm/lpc176x/include/adc.h
Executable file
@@ -0,0 +1,60 @@
|
||||
/**
|
||||
* @file adc.h
|
||||
*
|
||||
* @ingroup lpc176x
|
||||
*
|
||||
* @brief ADC library for the lpc176x bsp.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Taller Technologies.
|
||||
*
|
||||
* @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifndef LPC176X_ADC_H
|
||||
#define LPC176X_ADC_H
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/common-types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @brief Opens and initializes the ADC device.
|
||||
*
|
||||
* @param adc_number The ADC pin number to be initialized.
|
||||
* @return RTEMS_SUCCESSFUL if the initialization was succesful,
|
||||
* RTEMS_INVALID_NUMBER if wrong parameter.
|
||||
*/
|
||||
rtems_status_code adc_open( const lpc176x_pin_number pin_number );
|
||||
|
||||
/**
|
||||
* @brief Closes the ADC device.
|
||||
*
|
||||
* @return RTEMS_SUCCESSFUL if closed succesfully.
|
||||
*/
|
||||
rtems_status_code adc_close( void );
|
||||
|
||||
/**
|
||||
* @brief Starts a conversion, waits for it to finish and reads the value.
|
||||
*
|
||||
* @param pin_number The port to read the value.
|
||||
* @param result The read result. (In a percentage between 0.0f and 1.0f).
|
||||
*/
|
||||
rtems_status_code adc_read(
|
||||
const lpc176x_pin_number pin_number ,
|
||||
float *const result
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
183
c/src/lib/libbsp/arm/lpc176x/include/can-defs.h
Executable file
183
c/src/lib/libbsp/arm/lpc176x/include/can-defs.h
Executable file
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* @file can-defs.h
|
||||
*
|
||||
* @ingroup lpc176x
|
||||
*
|
||||
* @brief CAN controller for the lpc176x controller.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Taller Technologies.
|
||||
*
|
||||
* @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
|
||||
* @author Daniel Chicco (daniel.chicco@tallertechnologies.com)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifndef LPC176X_TIMER_DEFS_H
|
||||
#define LPC176X_TIMER_DEFS_H
|
||||
|
||||
#include <bsp/common-types.h>
|
||||
#include <bsp/can.h>
|
||||
|
||||
/* CAN ACCEPTANCE FILTER */
|
||||
#define CAN_ACCEPT_BASE_ADDR 0x4003C000
|
||||
|
||||
#define CAN_DRIVER_IS_MINOR_VALID( minor ) ( minor < CAN_DEVICES_NUMBER )
|
||||
#define CAN_DEFAULT_BAUD_RATE 1000000u
|
||||
#define CAN_DEFAULT_INTERRUPT_CONFIGURATION 0
|
||||
|
||||
#define MAX_NUMBER_OF_CAN_BITS 25u
|
||||
#define MIN_NUMBER_OF_CAN_BITS 4u
|
||||
#define CAN_BRP_EXTRA_BIT 1u
|
||||
#define CAN_TSEG_EXTRA_BITS 3u
|
||||
#define MAX_TSEG1_TSEG2_BITS 22u
|
||||
|
||||
#define CAN_GSR_RBS_MASK 1u
|
||||
#define CAN_CMR_RRB_MASK 4u
|
||||
|
||||
#define CAN_MAXIMUM_DATA_SIZE 8u
|
||||
#define CAN10_MAXIMUM_ID 0x7FFu
|
||||
|
||||
/**
|
||||
* @brief The Time segments of a CAN bit.
|
||||
*/
|
||||
typedef enum {
|
||||
CAN_TSEG1,
|
||||
CAN_TSEG2,
|
||||
CAN_NUMBER_OF_TSEG,
|
||||
} can_tseg_number;
|
||||
|
||||
#define CAN_BTR_TSEG1_SHIFT 16u
|
||||
#define CAN_BTR_TSEG2_SHIFT 20u
|
||||
#define CAN_BTR_SJW_SHIFT 14u
|
||||
#define CAN_BTR_BRP_SHIFT 0u
|
||||
|
||||
#define CAN_BTR_TSEG1_MASK 0x000F0000U
|
||||
#define CAN_BTR_TSEG2_MASK 0x00700000U
|
||||
#define CAN_BTR_SJW_MASK 0x0000C000U
|
||||
#define CAN_BTR_BRP_MASK 0x000003FFU
|
||||
|
||||
#define WRONG_BTR_VALUE 0xFFFFFFFF
|
||||
|
||||
/**
|
||||
* @brief The transmit buffers of the CAN device.
|
||||
*/
|
||||
typedef enum {
|
||||
CAN_TRANSMIT1,
|
||||
CAN_TRANSMIT2,
|
||||
CAN_TRANSMIT3,
|
||||
CAN_NUMBER_OF_TRANSMIT_BUFFERS
|
||||
} can_transmit_number;
|
||||
|
||||
/**
|
||||
* @brief The CAN status and control masks to send a message
|
||||
* for each transmit buffer.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t can_status_mask;
|
||||
uint32_t not_cc_cmr_value;
|
||||
} can_transmit_info;
|
||||
|
||||
/** @brief Represents the CAN controller registers.*/
|
||||
typedef struct {
|
||||
volatile uint32_t MOD;
|
||||
volatile uint32_t CMR;
|
||||
volatile uint32_t GSR;
|
||||
volatile uint32_t ICR;
|
||||
volatile uint32_t IER;
|
||||
volatile uint32_t BTR;
|
||||
volatile uint32_t EWL;
|
||||
volatile uint32_t SR;
|
||||
volatile registers_can_message receive;
|
||||
volatile registers_can_message transmit[ CAN_NUMBER_OF_TRANSMIT_BUFFERS ];
|
||||
} can_device;
|
||||
|
||||
/**
|
||||
* @brief A TX or RX pin for each CAN device .
|
||||
*/
|
||||
typedef enum {
|
||||
CAN_TX_PIN,
|
||||
CAN_RX_PIN,
|
||||
NUMBER_OF_CAN_PINS
|
||||
} can_pin_number;
|
||||
|
||||
/**
|
||||
* @brief A driver entry for each low level device.
|
||||
*/
|
||||
typedef struct {
|
||||
can_device *const device;
|
||||
const lpc176x_module module;
|
||||
const uint32_t pconp_pin;
|
||||
const uint32_t pins[ NUMBER_OF_CAN_PINS ];
|
||||
const lpc176x_pin_function pinfunction;
|
||||
} can_driver_entry;
|
||||
|
||||
/** @brief Represents the CAN centralized registers. */
|
||||
typedef struct {
|
||||
volatile uint32_t TX_SR;
|
||||
volatile uint32_t RX_SR;
|
||||
volatile uint32_t MSR;
|
||||
} can_central;
|
||||
|
||||
/** @brief Represents the acceptance filter registers. */
|
||||
typedef struct {
|
||||
volatile uint32_t AFMR;
|
||||
volatile uint32_t SFF_SA;
|
||||
volatile uint32_t SFF_GRP_SA;
|
||||
volatile uint32_t EFF_SA;
|
||||
volatile uint32_t EFF_GRP_SA;
|
||||
volatile uint32_t EOT;
|
||||
volatile uint32_t LUT_ERR_ADR;
|
||||
volatile uint32_t LUT_ERR;
|
||||
volatile uint32_t FCANIE;
|
||||
volatile uint32_t FCANIC0;
|
||||
volatile uint32_t FCANIC1;
|
||||
} can_acceptance_filter;
|
||||
|
||||
/**
|
||||
* @brief The possible CAN formats for a message.
|
||||
*/
|
||||
typedef enum {
|
||||
CANStandard = 0,
|
||||
CANExtended = 1,
|
||||
CANAny = 2
|
||||
} can_format;
|
||||
|
||||
/**
|
||||
* @brief The types of message.
|
||||
*/
|
||||
typedef enum {
|
||||
CANData = 0,
|
||||
CANRemote = 1
|
||||
} can_type;
|
||||
|
||||
#define CAN_INTERRUPT_TYPE_MASK 0x1ffu
|
||||
|
||||
/**
|
||||
* @brief The vector with all the callbacks for the CAN isr.
|
||||
*/
|
||||
typedef lpc176x_can_isr lpc176x_can_isr_vector[ CAN_IRQ_NUMBER ];
|
||||
|
||||
#define CAN_MOD_RM 0x00000001U
|
||||
|
||||
#define CAN_ACCF_AFMR_ACCOF 0x00000001U
|
||||
#define CAN_ACCF_AFMR_ACCBP 0x00000002U
|
||||
#define CAN_ACCF_AFMR_EFCAN 0x00000004U
|
||||
|
||||
#define CAN_IER_RIE 0x000000001U
|
||||
#define CAN_IER_TIE1 0x000000002U
|
||||
#define CAN_IER_EIE 0x000000004U
|
||||
#define CAN_IER_DOIE 0x000000008U
|
||||
#define CAN_IER_WUIE 0x000000010U
|
||||
#define CAN_IER_EPIEX 0x000000020U
|
||||
#define CAN_IER_ALIEX 0x000000040U
|
||||
#define CAN_IER_BEIEX 0x000000080U
|
||||
#define CAN_IER_IDIEX 0x000000100U
|
||||
#define CAN_IER_TIE2 0x000000200U
|
||||
#define CAN_IER_TIE3 0x000000400U
|
||||
|
||||
#endif /*LPC176X_TIMER_DEFS_H*/
|
||||
179
c/src/lib/libbsp/arm/lpc176x/include/can.h
Executable file
179
c/src/lib/libbsp/arm/lpc176x/include/can.h
Executable file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* @file can.h
|
||||
*
|
||||
* @ingroup lpc176x
|
||||
*
|
||||
* @brief CAN controller for the mbed lpc1768 board.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Taller Technologies.
|
||||
*
|
||||
* @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
|
||||
* @author Daniel Chicco (daniel.chicco@tallertechnologies.com)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifndef LPC176X_CAN_H
|
||||
#define LPC176X_CAN_H
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/io.h>
|
||||
#include <bsp/lpc176x.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @brief The CAN devices of the board.
|
||||
*/
|
||||
typedef enum {
|
||||
CAN_0,
|
||||
CAN_1,
|
||||
CAN_DEVICES_NUMBER
|
||||
} lpc176x_can_number;
|
||||
|
||||
/**
|
||||
* @brief A CAN message represented for the registers of the device.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t info;
|
||||
uint32_t id;
|
||||
uint32_t data_a;
|
||||
uint32_t data_b;
|
||||
} registers_can_message;
|
||||
|
||||
/**
|
||||
* @brief A CAN message represented with each logical parts
|
||||
*/
|
||||
typedef struct {
|
||||
unsigned int reserved1 : 16;
|
||||
unsigned int dlc : 4; /* Bits 16..19: DLC - Data Length Counter*/
|
||||
unsigned int reserved0 : 10;
|
||||
unsigned int rtr : 1; /* Bit 30: Set if this is a RTR message*/
|
||||
unsigned int type : 1; /* Bit 31: Set if this is a 29-bit ID message*/
|
||||
unsigned int id; /* CAN Message ID (11-bit or 29-bit)*/
|
||||
unsigned char data[ 8 ]; /* CAN Message Data Bytes 0-7*/
|
||||
} low_level_can_message;
|
||||
|
||||
/**
|
||||
* @brief A CAN message represented of both forms.
|
||||
*/
|
||||
typedef union {
|
||||
low_level_can_message low_level;
|
||||
registers_can_message registers;
|
||||
} can_message;
|
||||
|
||||
/**
|
||||
* @brief The possible interrupt sources for CAN.
|
||||
*/
|
||||
typedef enum {
|
||||
IRQ_RX = 0,
|
||||
IRQ_TX,
|
||||
IRQ_ERROR,
|
||||
IRQ_OVERRUN,
|
||||
IRQ_WAKEUP,
|
||||
IRQ_PASSIVE,
|
||||
IRQ_ARB,
|
||||
IRQ_BUS,
|
||||
IRQ_READY,
|
||||
CAN_IRQ_NUMBER
|
||||
} can_irq_type;
|
||||
|
||||
/**
|
||||
* @brief An isr for a CAN interrupt
|
||||
*
|
||||
* @param number The CAN which rised the interrupt.
|
||||
*/
|
||||
typedef void (*lpc176x_can_isr) ( lpc176x_can_number number );
|
||||
|
||||
/**
|
||||
* @brief A CAN frequency value
|
||||
*/
|
||||
typedef unsigned int can_freq;
|
||||
|
||||
/**
|
||||
* @brief Opens CAN device.
|
||||
* @details It enables the module and gives it a clock, sets the pins,
|
||||
* disables the interrupts, sets the frequency and bypasses
|
||||
* the acceptance filter.
|
||||
*
|
||||
* @param minor The device to open.
|
||||
* @param freq The desired frequency.
|
||||
* @return RTEMS_SUCCESFUL on success.
|
||||
*/
|
||||
rtems_status_code can_open( lpc176x_can_number minor, can_freq freq );
|
||||
|
||||
/**
|
||||
* @brief Closes the passed CAN device and shut it down.
|
||||
*
|
||||
* @param minor The device to close.
|
||||
* @return RTEMS_SUCCESSFUL if ok, RTEMS_INVALID_NUMBER for a bad parameter.
|
||||
*/
|
||||
rtems_status_code can_close( lpc176x_can_number minor );
|
||||
|
||||
/**
|
||||
* @brief Reads the CAN device.
|
||||
*
|
||||
* @param minor The CAN device to read.
|
||||
* @param message The read message.
|
||||
* @return RTEMS_SUCCESSFUL if read ok, RTEMS_IO_ERROR otherwise.
|
||||
*/
|
||||
rtems_status_code can_read(
|
||||
const lpc176x_can_number minor,
|
||||
can_message *message
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Writes the passed CAN message into the selected CAN device.
|
||||
*
|
||||
* @param minor The device to write.
|
||||
* @param message The message to write.
|
||||
* @return RTEMS_SUCCESFUL if write ok. RTEMS_IO_ERROR otherwise.
|
||||
*/
|
||||
rtems_status_code can_write(
|
||||
const lpc176x_can_number minor,
|
||||
const can_message *const message
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Registers an isr in the driver vector, and enables the interrupt
|
||||
* in the device.
|
||||
*
|
||||
* @param number The CAN device to set
|
||||
* @param type The interrupt type.
|
||||
* @param isr The isr to register.
|
||||
* @return RTEMS_SUCCESSFUL if ok RTEMS_INVALID_NUMBER otherwise.
|
||||
*/
|
||||
rtems_status_code can_register_isr(
|
||||
const lpc176x_can_number number,
|
||||
const can_irq_type type,
|
||||
const lpc176x_can_isr isr
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Creates a CAN message.
|
||||
* @details [long description]
|
||||
*
|
||||
* @param msg The created message.
|
||||
* @param _id The can id for the message.
|
||||
* @param _data The data of the message.
|
||||
* @param _len The lenght of the message.
|
||||
* @return RTEMS_SUCCESFUL if created, RTEMS_INVALID_NUMBER otherwise.
|
||||
*/
|
||||
rtems_status_code create_can_message(
|
||||
can_message *const msg,
|
||||
const int _id,
|
||||
const char *const _data,
|
||||
const char _len
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* ifndef LPC176X_CAN_H */
|
||||
@@ -46,6 +46,7 @@ typedef enum {
|
||||
LPC176X_MODULE_ADC,
|
||||
LPC176X_MODULE_CAN_0,
|
||||
LPC176X_MODULE_CAN_1,
|
||||
LPC176X_MODULE_ACCF,
|
||||
LPC176X_MODULE_DAC,
|
||||
LPC176X_MODULE_GPDMA,
|
||||
LPC176X_MODULE_GPIO,
|
||||
|
||||
@@ -43,6 +43,12 @@ extern "C" {
|
||||
#define LPC176X_PIN_SELECT_MASK_SIZE 2U
|
||||
#define LPC176X_PIN_UART_0_TXD 2U
|
||||
#define LPC176X_PIN_UART_0_RXD 3U
|
||||
#define LPC176X_PIN_UART_1_TXD 15U
|
||||
#define LPC176X_PIN_UART_1_RXD 16U
|
||||
#define LPC176X_PIN_UART_2_TXD 10U
|
||||
#define LPC176X_PIN_UART_2_RXD 11U
|
||||
#define LPC176X_PIN_UART_3_TXD 0U
|
||||
#define LPC176X_PIN_UART_3_RXD 1U
|
||||
|
||||
#define LPC176X_MODULE_BITS_COUNT 32U
|
||||
#define LPC176X_MODULE_COUNT ( LPC176X_MODULE_USB + 1U )
|
||||
@@ -68,6 +74,19 @@ typedef enum {
|
||||
}
|
||||
lpc176x_pin_function;
|
||||
|
||||
/**
|
||||
* @brief Defines the pin modes.
|
||||
*
|
||||
*/
|
||||
typedef enum {
|
||||
LPC176X_PIN_MODE_PULLUP,
|
||||
LPC176X_PIN_MODE_REPEATER,
|
||||
LPC176X_PIN_MODE_NONE,
|
||||
LPC176X_PIN_MODE_PULLDOWN,
|
||||
LPC176X_PIN_MODE_COUNT
|
||||
}
|
||||
lpc176x_pin_mode;
|
||||
|
||||
/**
|
||||
* @brief Defines all type of pins.
|
||||
*
|
||||
|
||||
@@ -31,7 +31,7 @@ extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @brief Set pin to the selected function.
|
||||
* @brief Sets pin to the selected function.
|
||||
*
|
||||
* @param pin The pin to set.
|
||||
* @param function Defines the function to set.
|
||||
@@ -41,6 +41,17 @@ void lpc176x_pin_select(
|
||||
lpc176x_pin_function function
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Sets pin to the selected mode.
|
||||
*
|
||||
* @param pin The pin to set.
|
||||
* @param mode Defines the mode to set.
|
||||
*/
|
||||
void lpc176x_pin_set_mode(
|
||||
const uint32_t pin,
|
||||
const lpc176x_pin_mode mode
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Enables the module power and clock.
|
||||
*
|
||||
|
||||
@@ -176,12 +176,12 @@ typedef struct {
|
||||
#define LPC176X_SCB_PBOOST_BOOST BSP_BIT32( 0 )
|
||||
#define LPC176X_SCB_CLKOUTCFG_CLKOUTSEL( val ) BSP_FLD32( val, 3, 0 )
|
||||
#define LPC176X_SCB_CLKOUTCFG_CLKOUTSEL_GET( reg ) BSP_FLD32GET( reg, 3, 0 )
|
||||
#define LPC176X_SCB_CLKOUTCFG_CLKOUTSEL_SET( reg, val ) BSP_FLD32SET( reg, val, \
|
||||
3, 0 )
|
||||
#define LPC176X_SCB_CLKOUTCFG_CLKOUTSEL_SET( reg, val ) BSP_FLD32SET( reg, \
|
||||
val, 3, 0 )
|
||||
#define LPC176X_SCB_CLKOUTCFG_CLKOUTDIV( val ) BSP_FLD32( val, 7, 4 )
|
||||
#define LPC176X_SCB_CLKOUTCFG_CLKOUTDIV_GET( reg ) BSP_FLD32GET( reg, 7, 4 )
|
||||
#define LPC176X_SCB_CLKOUTCFG_CLKOUTDIV_SET( reg, val ) BSP_FLD32SET( reg, val, \
|
||||
7, 4 )
|
||||
#define LPC176X_SCB_CLKOUTCFG_CLKOUTDIV_SET( reg, val ) BSP_FLD32SET( reg, \
|
||||
val, 7, 4 )
|
||||
#define LPC176X_SCB_CLKOUTCFG_CLKOUT_EN BSP_BIT32( 8 )
|
||||
#define LPC176X_SCB_CLKOUTCFG_CLKOUT_ACT BSP_BIT32( 9 )
|
||||
|
||||
|
||||
50
c/src/lib/libbsp/arm/lpc176x/include/mbed-pinmap.h
Executable file
50
c/src/lib/libbsp/arm/lpc176x/include/mbed-pinmap.h
Executable file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @file mbed-pinmap.h
|
||||
*
|
||||
* @ingroup lpc176x
|
||||
*
|
||||
* @brief Pins of the mbed lpc1768
|
||||
* See http://mbed.org/media/uploads/chris/mbed-005.1.pdf for references
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Taller Technologies.
|
||||
*
|
||||
* @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
|
||||
* @author Daniel Chicco (daniel.chicco@tallertechnologies.com)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#define DIP5 9U
|
||||
#define DIP6 8U
|
||||
#define DIP7 7U
|
||||
#define DIP8 6U
|
||||
#define DIP9 0U
|
||||
#define DIP10 1U
|
||||
#define DIP11 18U
|
||||
#define DIP12 17U
|
||||
#define DIP13 15U
|
||||
#define DIP14 16U
|
||||
#define DIP15 23U
|
||||
#define DIP16 24U
|
||||
#define DIP17 25U
|
||||
#define DIP18 26U
|
||||
#define DIP19 62U
|
||||
#define DIP20 63U
|
||||
#define DIP21 69U
|
||||
#define DIP22 68U
|
||||
#define DIP23 67U
|
||||
#define DIP24 66U
|
||||
#define DIP25 65U
|
||||
#define DIP26 64U
|
||||
#define DIP27 11U
|
||||
#define DIP28 10U
|
||||
#define DIP29 5U
|
||||
#define DIP30 4U
|
||||
#define LED1 50U
|
||||
#define LED2 52U
|
||||
#define LED3 53U
|
||||
#define LED4 55U
|
||||
105
c/src/lib/libbsp/arm/lpc176x/include/pwmout-defs.h
Executable file
105
c/src/lib/libbsp/arm/lpc176x/include/pwmout-defs.h
Executable file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @file pwmout-defs.h
|
||||
*
|
||||
* @ingroup lpc176x
|
||||
*
|
||||
* @brief PWM-Out controller for the mbed lpc1768 board.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Taller Technologies.
|
||||
*
|
||||
* @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifndef LPC176X_PWMOUT_DEFS_H
|
||||
#define LPC176X_PWMOUT_DEFS_H
|
||||
|
||||
#include <bsp/lpc176x.h>
|
||||
#include <bsp/pwmout.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#define PWM_DEFAULT_PERIOD 20000u
|
||||
#define PWM_DEFAULT_PULSEWIDTH 0u
|
||||
|
||||
#define PWM_PRESCALER_USECOND ( LPC176X_CCLK / 1000000 )
|
||||
#define PWM_MCR_RESET_ON_MATCH0 ( 1 << 1 )
|
||||
#define PWM_PCR_ENABLE_PWM( pwmout ) ( 1 << ( 9 + pwmout ) )
|
||||
#define PWM_TCR_RESET ( 1 << 1 )
|
||||
#define PWM_TCR_ENABLE ( 1u )
|
||||
#define PWM_TCR_PWM ( 1 << 3 )
|
||||
#define PWM_LER_LATCH_MATCH_0 1u
|
||||
#define PWM_LER_LATCH( match ) ( 1 << ( ( match ) + 1 ) )
|
||||
|
||||
/**
|
||||
* @brief The low-level PWM output device.
|
||||
*/
|
||||
typedef struct {
|
||||
volatile uint32_t IR;
|
||||
volatile uint32_t TCR;
|
||||
volatile uint32_t TC;
|
||||
volatile uint32_t PR;
|
||||
volatile uint32_t PC;
|
||||
volatile uint32_t MCR;
|
||||
volatile uint32_t MR0;
|
||||
volatile uint32_t MR1;
|
||||
volatile uint32_t MR2;
|
||||
volatile uint32_t MR3;
|
||||
volatile uint32_t CCR;
|
||||
volatile uint32_t CR0;
|
||||
volatile uint32_t CR1;
|
||||
volatile uint32_t CR2;
|
||||
volatile uint32_t CR3;
|
||||
volatile uint32_t RESERVED0;
|
||||
volatile uint32_t MR4;
|
||||
volatile uint32_t MR5;
|
||||
volatile uint32_t MR6;
|
||||
volatile uint32_t PCR;
|
||||
volatile uint32_t LER;
|
||||
volatile uint32_t RESERVED1[ 7 ];
|
||||
volatile uint32_t CTCR;
|
||||
} lpc176x_pwm_device;
|
||||
|
||||
/**
|
||||
* @brief Represents one pin and the respective function to be set
|
||||
* for each PWM output.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t pin_number;
|
||||
lpc176x_pin_function pin_function;
|
||||
} lpc176x_pwm_pin;
|
||||
|
||||
/**
|
||||
* @brief The PWM outputs of the board.
|
||||
*/
|
||||
typedef enum {
|
||||
PWMO_1,
|
||||
PWMO_2,
|
||||
PWMO_3,
|
||||
PWMO_4,
|
||||
PWMO_5,
|
||||
PWMO_6,
|
||||
PWM_OUTPUT_NUMBER
|
||||
} lpc176x_pwm_number;
|
||||
|
||||
/**
|
||||
* @brief A pin for each PWM output.
|
||||
*/
|
||||
typedef enum {
|
||||
PWM_FIRST_PIN,
|
||||
PWM_SECOND_PIN,
|
||||
PWM_NUMBER_OF_PINS
|
||||
} lpc176x_pwm_pin_number;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
73
c/src/lib/libbsp/arm/lpc176x/include/pwmout.h
Executable file
73
c/src/lib/libbsp/arm/lpc176x/include/pwmout.h
Executable file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* @file pwmout.h
|
||||
*
|
||||
* @ingroup lpc176x
|
||||
*
|
||||
* @brief PWM-Out controller for the mbed lpc1768 board.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Taller Technologies.
|
||||
*
|
||||
* @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#ifndef LPC176X_PWMOUT_H
|
||||
#define LPC176X_PWMOUT_H
|
||||
|
||||
#include <bsp.h>
|
||||
#include <bsp/io.h>
|
||||
#include <bsp/lpc176x.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @brief Initializes the PWM output device and sets an initial period
|
||||
* of 20000us.
|
||||
*
|
||||
* @param pin_number The PWM output pin.
|
||||
* @return RTEMS_SUCCESSFULL if the PWM initialization was OK,
|
||||
* RTEMS_INVALID_NUMBER for a wrong parameter.
|
||||
*/
|
||||
rtems_status_code pwm_init( const lpc176x_pin_number pin_number );
|
||||
|
||||
/**
|
||||
* @brief Sets a period for the PWM output. (Note that this changes the period
|
||||
* for all the PWM outputs.)
|
||||
*
|
||||
* @param pin_number The pin whose period we want to change.
|
||||
* @param period The desired period in microseconds.
|
||||
*
|
||||
* @return RTEMS_SUCCESSFULL if the period's setting was OK,
|
||||
* RTEMS_INVALID_NUMBER for a bad parameter.
|
||||
*/
|
||||
rtems_status_code pwm_period(
|
||||
const lpc176x_pin_number pin_number,
|
||||
const lpc176x_microseconds period
|
||||
);
|
||||
|
||||
/**
|
||||
* @brief Sets a pulsewidth for the PWM output.
|
||||
*
|
||||
* @param pin_number The pin whose pulsewidth we want to change.
|
||||
* @param pwidth The desired pulsewidth in microseconds.
|
||||
*
|
||||
* @return RTEMS_SUCCESSFULL if the pulsewidth's setting was OK,
|
||||
* RTEMS_INVALID_NUMBER for a wrong parameter.
|
||||
*/
|
||||
rtems_status_code pwm_pulsewidth(
|
||||
const lpc176x_pin_number pin_number,
|
||||
const lpc176x_microseconds pwidth
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
||||
@@ -33,6 +33,7 @@ static const lpc176x_module_entry lpc176x_module_table[] = {
|
||||
LPC176X_MODULE_ENTRY( LPC176X_MODULE_ADC, 1, 1, 12 ),
|
||||
LPC176X_MODULE_ENTRY( LPC176X_MODULE_CAN_0, 1, 1, 13 ),
|
||||
LPC176X_MODULE_ENTRY( LPC176X_MODULE_CAN_1, 1, 1, 14 ),
|
||||
LPC176X_MODULE_ENTRY(LPC176X_MODULE_ACCF, 0, 1, 15),
|
||||
LPC176X_MODULE_ENTRY( LPC176X_MODULE_DAC, 0, 1, 11 ),
|
||||
LPC176X_MODULE_ENTRY( LPC176X_MODULE_GPDMA, 1, 1, 29 ),
|
||||
LPC176X_MODULE_ENTRY( LPC176X_MODULE_GPIO, 0, 1, 15 ),
|
||||
@@ -70,6 +71,20 @@ inline void lpc176x_pin_select(
|
||||
LPC176X_PIN_SELECT_MASK << shift, shift );
|
||||
}
|
||||
|
||||
void lpc176x_pin_set_mode(
|
||||
const uint32_t pin,
|
||||
const lpc176x_pin_mode mode
|
||||
)
|
||||
{
|
||||
assert( pin <= LPC176X_IO_INDEX_MAX
|
||||
&& mode < LPC176X_PIN_MODE_COUNT );
|
||||
const uint32_t pin_selected = LPC176X_PIN_SELECT( pin );
|
||||
volatile uint32_t *const pinmode = &LPC176X_PINMODE[ pin_selected ];
|
||||
const uint32_t shift = LPC176X_PIN_SELECT_SHIFT( pin );
|
||||
*pinmode = SET_FIELD( *pinmode, mode,
|
||||
LPC176X_PIN_SELECT_MASK << shift, shift );
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if the module has power.
|
||||
*
|
||||
|
||||
@@ -117,6 +117,30 @@ $(PROJECT_INCLUDE)/bsp/gpio.h: include/gpio.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gpio.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/gpio.h
|
||||
|
||||
$(PROJECT_INCLUDE)/bsp/can.h: include/can.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/can.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/can.h
|
||||
|
||||
$(PROJECT_INCLUDE)/bsp/can-defs.h: include/can-defs.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/can-defs.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/can-defs.h
|
||||
|
||||
$(PROJECT_INCLUDE)/bsp/pwmout.h: include/pwmout.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/pwmout.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/pwmout.h
|
||||
|
||||
$(PROJECT_INCLUDE)/bsp/pwmout-defs.h: include/pwmout-defs.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/pwmout-defs.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/pwmout-defs.h
|
||||
|
||||
$(PROJECT_INCLUDE)/bsp/adc.h: include/adc.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/adc.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/adc.h
|
||||
|
||||
$(PROJECT_INCLUDE)/bsp/adc-defs.h: include/adc-defs.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/adc-defs.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/adc-defs.h
|
||||
|
||||
$(PROJECT_INCLUDE)/bsp/timer-defs.h: include/timer-defs.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/timer-defs.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/timer-defs.h
|
||||
@@ -149,6 +173,10 @@ $(PROJECT_INCLUDE)/bsp/system-clocks.h: include/system-clocks.h $(PROJECT_INCLUD
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/system-clocks.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/system-clocks.h
|
||||
|
||||
$(PROJECT_INCLUDE)/bsp/mbed-pinmap.h: include/mbed-pinmap.h $(PROJECT_INCLUDE)/bsp/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/mbed-pinmap.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/mbed-pinmap.h
|
||||
|
||||
$(PROJECT_INCLUDE)/tm27.h: ../../shared/include/tm27.h $(PROJECT_INCLUDE)/$(dirstamp)
|
||||
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/tm27.h
|
||||
PREINSTALL_FILES += $(PROJECT_INCLUDE)/tm27.h
|
||||
|
||||
210
c/src/lib/libbsp/arm/lpc176x/pwmout/pwmout.c
Executable file
210
c/src/lib/libbsp/arm/lpc176x/pwmout/pwmout.c
Executable file
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* @file pwmout.c
|
||||
*
|
||||
* @ingroup lpc176x
|
||||
*
|
||||
* @brief PWM-Out controller for the mbed lpc1768 board.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (c) 2014 Taller Technologies.
|
||||
*
|
||||
* @author Diaz Marcos (marcos.diaz@tallertechnologies.com)
|
||||
*
|
||||
* The license and distribution terms for this file may be
|
||||
* found in the file LICENSE in this distribution or at
|
||||
* http://www.rtems.com/license/LICENSE.
|
||||
*/
|
||||
|
||||
#include <rtems/status-checks.h>
|
||||
#include <bsp/pwmout.h>
|
||||
#include <bsp/pwmout-defs.h>
|
||||
|
||||
/**
|
||||
* @brief The low level device.
|
||||
*/
|
||||
static lpc176x_pwm_device *const pwm_device = PWM1_BASE_ADDR;
|
||||
|
||||
/**
|
||||
* @brief The possible output pins for each PWM output.
|
||||
*/
|
||||
static const lpc176x_pwm_pin pwm_pins[ PWM_OUTPUT_NUMBER ][ PWM_NUMBER_OF_PINS
|
||||
] =
|
||||
{
|
||||
{ { 50u, LPC176X_PIN_FUNCTION_10 }, { 64u, LPC176X_PIN_FUNCTION_01 } },
|
||||
{ { 52u, LPC176X_PIN_FUNCTION_10 }, { 65u, LPC176X_PIN_FUNCTION_01 } },
|
||||
{ { 53u, LPC176X_PIN_FUNCTION_10 }, { 66u, LPC176X_PIN_FUNCTION_01 } },
|
||||
{ { 55u, LPC176X_PIN_FUNCTION_10 }, { 67u, LPC176X_PIN_FUNCTION_01 } },
|
||||
{ { 56u, LPC176X_PIN_FUNCTION_10 }, { 68u, LPC176X_PIN_FUNCTION_01 } },
|
||||
{ { 58u, LPC176X_PIN_FUNCTION_10 }, { 69u, LPC176X_PIN_FUNCTION_01 } },
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The pointers to the low level match registers for each PWM output.
|
||||
*/
|
||||
static volatile uint32_t *const pwm_match[ PWM_OUTPUT_NUMBER ] = {
|
||||
&PWM1MR1,
|
||||
&PWM1MR2,
|
||||
&PWM1MR3,
|
||||
&PWM1MR4,
|
||||
&PWM1MR5,
|
||||
&PWM1MR6
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Checks if a pin number is valid for the given PWM,
|
||||
* and sets the corresponding pin function for that pin.
|
||||
*
|
||||
* @param pin_number The pin number to search.
|
||||
* @param pwm In which PWM search for the pin number.
|
||||
* @param pin_function If the pin number is found, here we return
|
||||
* the pin function for that pin number.
|
||||
* @return True if found, false otherwise.
|
||||
*/
|
||||
static inline bool is_found_in_this_pwm(
|
||||
const lpc176x_pin_number pin_number,
|
||||
const lpc176x_pwm_number pwm,
|
||||
lpc176x_pin_function *const pin_function
|
||||
)
|
||||
{
|
||||
lpc176x_pwm_pin_number pnumber = PWM_FIRST_PIN;
|
||||
bool found = false;
|
||||
|
||||
while (!found && ( pnumber < PWM_NUMBER_OF_PINS ))
|
||||
{
|
||||
if ( pwm_pins[ pwm ][ pnumber ].pin_number == pin_number ) {
|
||||
found = true;
|
||||
*pin_function = pwm_pins[ pwm ][ pnumber ].pin_function;
|
||||
}/*else implies that the pin number was not found. Keep looking.*/
|
||||
++pnumber;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Checks if a pin number is valid for any PWM,
|
||||
* and sets the corresponding pin function for that pin.
|
||||
*
|
||||
* @param pin_number The pin number to search.
|
||||
* @param pwm If is found here we return in which PWM was found.
|
||||
* @param pin_function If the pin number is found the pin function
|
||||
* for this pin number one will be returned.
|
||||
* @return True if found, false otherwise.
|
||||
*/
|
||||
static bool is_valid_pin_number(
|
||||
const lpc176x_pin_number pin_number,
|
||||
lpc176x_pwm_number *const pwm,
|
||||
lpc176x_pin_function *const pin_function
|
||||
)
|
||||
{
|
||||
bool found = false;
|
||||
lpc176x_pwm_number pwm_local = PWMO_1;
|
||||
while(!found && ( pwm_local < PWM_OUTPUT_NUMBER ))
|
||||
{
|
||||
if ( is_found_in_this_pwm( pin_number, pwm_local, pin_function ) ) {
|
||||
*pwm = pwm_local;
|
||||
found = true;
|
||||
} /*else implies that the pin number was not found. Keep looking.*/
|
||||
++pwm_local;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the period for the given PWM.
|
||||
*
|
||||
* @param pwm The PWM output in which the period will be set.
|
||||
* @param period The period to set.
|
||||
*/
|
||||
static void set_period(
|
||||
const lpc176x_pwm_number pwm,
|
||||
const lpc176x_microseconds period
|
||||
)
|
||||
{
|
||||
pwm_device->TCR = PWM_TCR_RESET;
|
||||
pwm_device->MR0 = period * PWM_PRESCALER_USECOND;
|
||||
pwm_device->LER |= PWM_LER_LATCH_MATCH_0;
|
||||
pwm_device->TCR = PWM_TCR_PWM | PWM_TCR_ENABLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the pulsewidth for the given PWM.
|
||||
*
|
||||
* @param pwm The PWM output in which the pulsewidth will be set.
|
||||
* @param pwidth The pulse width to set.
|
||||
*/
|
||||
static void set_pulsewidth(
|
||||
const lpc176x_pwm_number pwm,
|
||||
lpc176x_microseconds pwidth
|
||||
)
|
||||
{
|
||||
pwidth *= PWM_PRESCALER_USECOND;
|
||||
|
||||
if ( pwm_device->MR0 == pwidth ) {
|
||||
++pwidth;
|
||||
} /* Not the same as the period, do nothing.*/
|
||||
|
||||
*( pwm_match[ pwm ] ) = pwidth;
|
||||
pwm_device->LER |= PWM_LER_LATCH( pwm );
|
||||
}
|
||||
|
||||
rtems_status_code pwm_init( const lpc176x_pin_number pin_number )
|
||||
{
|
||||
rtems_status_code sc = RTEMS_INVALID_NUMBER;
|
||||
lpc176x_pin_function pin_function;
|
||||
lpc176x_pwm_number pwm;
|
||||
|
||||
if ( is_valid_pin_number( pin_number, &pwm, &pin_function ) ) {
|
||||
sc = lpc176x_module_enable( LPC176X_MODULE_PWM_1,
|
||||
LPC176X_MODULE_PCLK_DEFAULT );
|
||||
RTEMS_CHECK_SC( sc, "enable pwm module" );
|
||||
|
||||
pwm_device->PR = 0;
|
||||
pwm_device->MCR = PWM_MCR_RESET_ON_MATCH0;
|
||||
pwm_device->PCR |= PWM_PCR_ENABLE_PWM( pwm );
|
||||
|
||||
set_period( pwm, PWM_DEFAULT_PERIOD );
|
||||
set_pulsewidth( pwm, PWM_DEFAULT_PULSEWIDTH );
|
||||
|
||||
lpc176x_pin_select( pin_number, pin_function );
|
||||
} /* else implies that the pin number is not valid.
|
||||
So, a RTEMS_INVALID_NUMBER will be returned.*/
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
rtems_status_code pwm_period(
|
||||
const lpc176x_pin_number pin_number,
|
||||
const lpc176x_microseconds period
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_INVALID_NUMBER;
|
||||
lpc176x_pin_function pin_function;
|
||||
lpc176x_pwm_number pwm;
|
||||
|
||||
if ( is_valid_pin_number( pin_number, &pwm, &pin_function ) ) {
|
||||
sc = RTEMS_SUCCESSFUL;
|
||||
set_period( pwm, period );
|
||||
} /* else implies that the pin number is not valid.
|
||||
So, a RTEMS_INVALID_NUMBER will be returned.*/
|
||||
|
||||
return sc;
|
||||
}
|
||||
|
||||
rtems_status_code pwm_pulsewidth(
|
||||
const lpc176x_pin_number pin_number,
|
||||
const lpc176x_microseconds pwidth
|
||||
)
|
||||
{
|
||||
rtems_status_code sc = RTEMS_INVALID_NUMBER;
|
||||
lpc176x_pin_function pin_function;
|
||||
lpc176x_pwm_number pwm;
|
||||
|
||||
if ( is_valid_pin_number( pin_number, &pwm, &pin_function ) ) {
|
||||
sc = RTEMS_SUCCESSFUL;
|
||||
set_pulsewidth( pwm, pwidth );
|
||||
} /* Else wrong pin_number return RTEMS_INVALID_NUMBER*/
|
||||
|
||||
return sc;
|
||||
}
|
||||
@@ -51,8 +51,8 @@
|
||||
CONSOLE_LCR = 0x00; \
|
||||
CONSOLE_IER = 0x00; \
|
||||
CONSOLE_LCR = 0x80; \
|
||||
CONSOLE_DLL = (dll); \
|
||||
CONSOLE_DLM = 0x00; \
|
||||
CONSOLE_DLL = (dll & 0xFF); \
|
||||
CONSOLE_DLM = (dll >> 8); \
|
||||
CONSOLE_LCR = 0x03; \
|
||||
CONSOLE_FCR = 0x07; \
|
||||
} while (0)
|
||||
|
||||
Reference in New Issue
Block a user