mirror of https://github.com/ARMmbed/mbed-os.git
[LPC1347]: first implementation of PWMOut (not tested)
parent
721082257c
commit
6b7f4b998e
|
@ -206,6 +206,38 @@ typedef struct { /*!< (@ 0x40008000) USART Structure
|
|||
// ----- CT16B0 -----
|
||||
// ------------------------------------------------------------------------------------------------
|
||||
|
||||
typedef struct { /*!< (@ 0x4000C000) LPC_CTxxBx_Type Structure */
|
||||
__IO uint32_t IR; /*!< (@ 0x4000C000) Interrupt Register. The IR can be written to clear interrupts. The IR can be read to identify which of eight possible interrupt sources are pending. */
|
||||
__IO uint32_t TCR; /*!< (@ 0x4000C004) Timer Control Register. The TCR is used to control the Timer Counter functions. The Timer Counter can be disabled or reset through the TCR. */
|
||||
__IO uint32_t TC; /*!< (@ 0x4000C008) Timer Counter. The 16-bit TC is incremented every PR+1 cycles of PCLK. The TC is controlled through the TCR. */
|
||||
__IO uint32_t PR; /*!< (@ 0x4000C00C) Prescale Register. When the Prescale Counter (below) is equal to this value, the next clock increments the TC and clears the PC. */
|
||||
__IO uint32_t PC; /*!< (@ 0x4000C010) Prescale Counter. The 16-bit PC is a counter which is incremented to the value stored in PR. When the value in PR is reached, the TC is incremented and the PC is cleared. The PC is observable and controllable through the bus interface. */
|
||||
__IO uint32_t MCR; /*!< (@ 0x4000C014) Match Control Register. The MCR is used to control if an interrupt is generated and if the TC is reset when a Match occurs. */
|
||||
union {
|
||||
__IO uint32_t MR[4]; /*!< (@ 0x4000C018) Match Register. MR can be enabled through the MCR to reset the TC, stop both the TC and PC, and/or generate an interrupt every time MR matches the TC. */
|
||||
struct{
|
||||
__IO uint32_t MR0; /*!< (@ 0x4000C018) Match Register. MR0 */
|
||||
__IO uint32_t MR1; /*!< (@ 0x4000C01C) Match Register. MR1 */
|
||||
__IO uint32_t MR2; /*!< (@ 0x4000C020) Match Register. MR2 */
|
||||
__IO uint32_t MR3; /*!< (@ 0x4000C024) Match Register. MR3 */
|
||||
};
|
||||
};
|
||||
__IO uint32_t CCR; /*!< (@ 0x4000C028) Capture Control Register. The CCR controls which edges of the capture inputs are used to load the Capture Registers and whether or not an interrupt is generated when a capture takes place. */
|
||||
union{
|
||||
__I uint32_t CR[4]; /*!< (@ 0x4000C02C) Capture Register. CR is loaded with the value of TC when there is an event on the CT16B0_CAP input. */
|
||||
struct{
|
||||
__I uint32_t CR0; /*!< (@ 0x4000C02C) Capture Register. CR 0 */
|
||||
__I uint32_t CR1; /*!< (@ 0x4000C030) Capture Register. CR 1 */
|
||||
__I uint32_t CR2; /*!< (@ 0x4000C034) Capture Register. CR 2 */
|
||||
__I uint32_t CR3; /*!< (@ 0x4000C038) Capture Register. CR 3 */
|
||||
};
|
||||
};
|
||||
__IO uint32_t EMR; /*!< (@ 0x4000C03C) External Match Register. The EMR controls the match function and the external match pins */
|
||||
__I uint32_t RESERVED0[12];
|
||||
__IO uint32_t CTCR; /*!< (@ 0x4000C070) Count Control Register. The CTCR selects between Timer and Counter mode, and in Counter mode selects the signal and edge(s) for counting. */
|
||||
__IO uint32_t PWMC; /*!< (@ 0x4000C074) PWM Control Register. The PWMCON enables PWM mode for the external match pins CT16B0_MAT[1:0] and CT16B1_MAT[1:0]. */
|
||||
} LPC_CTxxBx_Type;
|
||||
|
||||
typedef struct { /*!< (@ 0x4000C000) CT16B0 Structure */
|
||||
__IO uint32_t IR; /*!< (@ 0x4000C000) Interrupt Register. The IR can be written to clear interrupts. The IR can be read to identify which of eight possible interrupt sources are pending. */
|
||||
__IO uint32_t TCR; /*!< (@ 0x4000C004) Timer Control Register. The TCR is used to control the Timer Counter functions. The Timer Counter can be disabled or reset through the TCR. */
|
||||
|
@ -713,10 +745,10 @@ typedef struct { /*!< (@ 0x50000000) GPIO_PORT Struct
|
|||
#define LPC_I2C ((LPC_I2C_Type *) LPC_I2C_BASE)
|
||||
#define LPC_WWDT ((LPC_WWDT_Type *) LPC_WWDT_BASE)
|
||||
#define LPC_USART ((LPC_USART_Type *) LPC_USART_BASE)
|
||||
#define LPC_CT16B0 ((LPC_CT16B0_Type *) LPC_CT16B0_BASE)
|
||||
#define LPC_CT16B1 ((LPC_CT16B1_Type *) LPC_CT16B1_BASE)
|
||||
#define LPC_CT32B0 ((LPC_CT32B0_Type *) LPC_CT32B0_BASE)
|
||||
#define LPC_CT32B1 ((LPC_CT32B1_Type *) LPC_CT32B1_BASE)
|
||||
#define LPC_CT16B0 ((LPC_CTxxBx_Type *) LPC_CT16B0_BASE)
|
||||
#define LPC_CT16B1 ((LPC_CTxxBx_Type *) LPC_CT16B1_BASE)
|
||||
#define LPC_CT32B0 ((LPC_CTxxBx_Type *) LPC_CT32B0_BASE)
|
||||
#define LPC_CT32B1 ((LPC_CTxxBx_Type *) LPC_CT32B1_BASE)
|
||||
#define LPC_ADC ((LPC_ADC_Type *) LPC_ADC_BASE)
|
||||
#define LPC_PMU ((LPC_PMU_Type *) LPC_PMU_BASE)
|
||||
#define LPC_FLASHCTRL ((LPC_FLASHCTRL_Type *) LPC_FLASHCTRL_BASE)
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
#define DEVICE_ETHERNET 0
|
||||
|
||||
#define DEVICE_PWMOUT 0
|
||||
#define DEVICE_PWMOUT 1
|
||||
|
||||
#define DEVICE_SEMIHOST 0
|
||||
#define DEVICE_LOCALFILESYSTEM 0
|
||||
|
|
|
@ -38,11 +38,11 @@ struct port_s {
|
|||
uint32_t mask;
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
struct pwmout_s {
|
||||
PWMName pwm;
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
struct serial_s {
|
||||
LPC_USART_Type *uart;
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2013 ARM Limited
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
#include "pwmout_api.h"
|
||||
#include "cmsis.h"
|
||||
#include "pinmap.h"
|
||||
#include "error.h"
|
||||
|
||||
#define TCR_CNT_EN 0x00000001
|
||||
#define TCR_RESET 0x00000002
|
||||
|
||||
/* To have a PWM where we can change both the period and the duty cycle,
|
||||
* we need an entire timer. With the following conventions:
|
||||
* * MR3 is used for the PWM period
|
||||
* * MR0, MR1, MR2 are used for the duty cycle
|
||||
*/
|
||||
static const PinMap PinMap_PWM[] = {
|
||||
/* CT16B0 */
|
||||
{P0_8 , PWM_1, 2}, {P1_13, PWM_1, 2}, /* MR0 */
|
||||
{P0_9 , PWM_2, 2}, {P1_14, PWM_2, 2}, /* MR1 */
|
||||
{P0_10, PWM_3, 3}, {P1_15, PWM_3, 2}, /* MR2 */
|
||||
|
||||
/* CT16B1 */
|
||||
{P0_21, PWM_4, 1}, /* MR0 */
|
||||
{P0_22, PWM_5, 2}, {P1_23, PWM_5, 1}, /* MR1 */
|
||||
|
||||
/* CT32B0 */
|
||||
{P0_18, PWM_6, 2}, {P1_24, PWM_6, 1}, /* MR0 */
|
||||
{P0_19, PWM_7, 2}, {P1_25, PWM_7, 1}, /* MR1 */
|
||||
{P0_1 , PWM_8, 2}, {P1_26, PWM_8, 1}, /* MR2 */
|
||||
|
||||
/* CT32B1 */
|
||||
{P0_13, PWM_9 , 3}, //{P1_0, PWM_9 , 1}, /* MR0 */
|
||||
{P0_14, PWM_10, 3}, //{P1_1, PWM_10, 1}, /* MR1 */
|
||||
{P0_15, PWM_11, 3}, //{P1_2, PWM_11, 1}, /* MR2 */
|
||||
|
||||
{NC, NC, 0}
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint8_t timer;
|
||||
uint8_t mr;
|
||||
} timer_mr;
|
||||
|
||||
static timer_mr pwm_timer_map[11] = {
|
||||
{0, 0}, {0, 1}, {0, 2},
|
||||
{1, 0}, {1, 1},
|
||||
{2, 0}, {2, 1}, {2, 2},
|
||||
{3, 0}, {3, 1}, {3, 2},
|
||||
};
|
||||
|
||||
static LPC_CTxxBx_Type *Timers[4] = {
|
||||
LPC_CT16B0, LPC_CT16B1,
|
||||
LPC_CT32B0, LPC_CT32B1
|
||||
};
|
||||
|
||||
static unsigned int pwm_clock_mhz;
|
||||
|
||||
void pwmout_init(pwmout_t* obj, PinName pin) {
|
||||
// determine the channel
|
||||
PWMName pwm = (PWMName)pinmap_peripheral(pin, PinMap_PWM);
|
||||
if (pwm == (uint32_t)NC)
|
||||
error("PwmOut pin mapping failed");
|
||||
|
||||
obj->pwm = pwm;
|
||||
|
||||
// Timer registers
|
||||
timer_mr tid = pwm_timer_map[pwm];
|
||||
LPC_CTxxBx_Type *timer = Timers[tid.timer];
|
||||
|
||||
// Disable timer
|
||||
timer->TCR = 0;
|
||||
|
||||
// Power the correspondent timer
|
||||
LPC_SYSCON->SYSAHBCLKCTRL |= 1 << (tid.timer + 7);
|
||||
|
||||
/* Enable PWM function */
|
||||
timer->PWMC = (1 << 3)|(1 << 2)|(1 << 1)|(1 << 0);
|
||||
|
||||
/* Reset Functionality on MR3 controlling the PWM period */
|
||||
timer->MCR = 1 << 10;
|
||||
|
||||
pwm_clock_mhz = SystemCoreClock / 1000000;
|
||||
|
||||
// default to 20ms: standard for servos, and fine for e.g. brightness control
|
||||
pwmout_period_ms(obj, 20);
|
||||
pwmout_write (obj, 0);
|
||||
|
||||
// Wire pinout
|
||||
pinmap_pinout(pin, PinMap_PWM);
|
||||
}
|
||||
|
||||
void pwmout_free(pwmout_t* obj) {
|
||||
// [TODO]
|
||||
}
|
||||
|
||||
void pwmout_write(pwmout_t* obj, float value) {
|
||||
if (value < 0.0f) {
|
||||
value = 0.0;
|
||||
} else if (value > 1.0f) {
|
||||
value = 1.0;
|
||||
}
|
||||
|
||||
timer_mr tid = pwm_timer_map[obj->pwm];
|
||||
LPC_CTxxBx_Type *timer = Timers[tid.timer];
|
||||
uint32_t t_off = timer->MR3 - (uint32_t)((float)(timer->MR3) * value);
|
||||
|
||||
timer->TCR = TCR_RESET;
|
||||
timer->MR[tid.mr] = t_off;
|
||||
timer->TCR = TCR_CNT_EN;
|
||||
}
|
||||
|
||||
float pwmout_read(pwmout_t* obj) {
|
||||
timer_mr tid = pwm_timer_map[obj->pwm];
|
||||
LPC_CTxxBx_Type *timer = Timers[tid.timer];
|
||||
|
||||
float v = (float)(timer->MR3 - timer->MR[tid.mr]) / (float)(timer->MR3);
|
||||
return (v > 1.0f) ? (1.0f) : (v);
|
||||
}
|
||||
|
||||
void pwmout_period(pwmout_t* obj, float seconds) {
|
||||
pwmout_period_us(obj, seconds * 1000000.0f);
|
||||
}
|
||||
|
||||
void pwmout_period_ms(pwmout_t* obj, int ms) {
|
||||
pwmout_period_us(obj, ms * 1000);
|
||||
}
|
||||
|
||||
// Set the PWM period, keeping the duty cycle the same.
|
||||
void pwmout_period_us(pwmout_t* obj, int us) {
|
||||
int i = 0;
|
||||
uint32_t period_ticks = pwm_clock_mhz * us;
|
||||
|
||||
timer_mr tid = pwm_timer_map[obj->pwm];
|
||||
LPC_CTxxBx_Type *timer = Timers[tid.timer];
|
||||
uint32_t old_period_ticks = timer->MR3;
|
||||
|
||||
timer->TCR = TCR_RESET;
|
||||
timer->MR3 = period_ticks;
|
||||
|
||||
// Scale the pulse width to preserve the duty ratio
|
||||
if (old_period_ticks > 0) {
|
||||
for (i=0; i<3; i++) {
|
||||
uint32_t t_off = period_ticks - (uint32_t)(((uint64_t)timer->MR[i] * (uint64_t)period_ticks) / (uint64_t)old_period_ticks);
|
||||
timer->MR[i] = t_off;
|
||||
}
|
||||
}
|
||||
timer->TCR = TCR_CNT_EN;
|
||||
}
|
||||
|
||||
void pwmout_pulsewidth(pwmout_t* obj, float seconds) {
|
||||
pwmout_pulsewidth_us(obj, seconds * 1000000.0f);
|
||||
}
|
||||
|
||||
void pwmout_pulsewidth_ms(pwmout_t* obj, int ms) {
|
||||
pwmout_pulsewidth_us(obj, ms * 1000);
|
||||
}
|
||||
|
||||
void pwmout_pulsewidth_us(pwmout_t* obj, int us) {
|
||||
uint32_t t_on = (uint32_t)(((uint64_t)SystemCoreClock * (uint64_t)us) / (uint64_t)1000000);
|
||||
timer_mr tid = pwm_timer_map[obj->pwm];
|
||||
LPC_CTxxBx_Type *timer = Timers[tid.timer];
|
||||
|
||||
timer->TCR = TCR_RESET;
|
||||
if (t_on > timer->MR3) {
|
||||
pwmout_period_us(obj, us);
|
||||
}
|
||||
uint32_t t_off = timer->MR3 - t_on;
|
||||
timer->MR[tid.mr] = t_off;
|
||||
timer->TCR = TCR_CNT_EN;
|
||||
}
|
Loading…
Reference in New Issue