LPC17xx_40xx PWM multichannel support

USB no softconnect
SocketCAN kconfig fixes
This commit is contained in:
Peter van der Perk 2022-08-04 19:20:59 +02:00 committed by Xiang Xiao
parent 6ab76bfc7c
commit 22d41f6b9c
9 changed files with 336 additions and 58 deletions

View File

@ -172,6 +172,9 @@ config ARCH_FAMILY_LPC408X
config LPC17_40_HAVE_SPIFI
bool
config LPC17_40_CAN
bool
menu "LPC17xx/LPC40xx Peripheral Support"
config LPC17_40_MAINOSC
@ -262,13 +265,13 @@ config LPC17_40_UART4
config LPC17_40_CAN1
bool "CAN1"
select LPC17_40_CAN
default n
select CAN
config LPC17_40_CAN2
bool "CAN2"
select LPC17_40_CAN
default n
select CAN
config LPC17_40_SPI
bool "SPI"
@ -345,6 +348,7 @@ config LPC17_40_PWM0
config LPC17_40_PWM1
bool "PWM1"
select ARCH_HAVE_PWM_MULTICHAN
default n
config LPC17_40_PWM1_PIN
@ -356,6 +360,48 @@ config LPC17_40_PWM1_PIN
If TIM1 is enabled for PWM usage, you also need specifies the timer output
channel {1,..,4}
config LPC17_40_PWM1_CHANNEL1
bool "PWM1 Channel 1"
default y
depends on LPC17_40_PWM1
---help---
Enable PWM1 channel 1, board has to define pin GPIO_PWM1p1
config LPC17_40_PWM1_CHANNEL2
bool "PWM1 Channel 2"
default n
depends on LPC17_40_PWM1
---help---
Enable PWM1 channel 2, board has to define pin GPIO_PWM1p2
config LPC17_40_PWM1_CHANNEL3
bool "PWM1 Channel 3"
default n
depends on LPC17_40_PWM1
---help---
Enable PWM1 channel 3, board has to define pin GPIO_PWM1p3
config LPC17_40_PWM1_CHANNEL4
bool "PWM1 Channel 4"
default n
depends on LPC17_40_PWM1
---help---
Enable PWM1 channel 4, board has to define pin GPIO_PWM1p4
config LPC17_40_PWM1_CHANNEL5
bool "PWM1 Channel 5"
default n
depends on LPC17_40_PWM1
---help---
Enable PWM1 channel 5, board has to define pin GPIO_PWM1p5
config LPC17_40_PWM1_CHANNEL6
bool "PWM1 Channel 6"
default n
depends on LPC17_40_PWM1
---help---
Enable PWM1 channel 6, board has to define pin GPIO_PWM1p6
config LPC17_40_MCPWM
bool "MCPWM"
default n
@ -649,7 +695,7 @@ config LPC17_40_ADC_NCHANNELS
endmenu
menu "CAN driver options"
depends on LPC17_40_CAN1 || LPC17_40_CAN2
depends on LPC17_40_CAN
config LPC17_40_CAN1_BAUD
int "CAN1 BAUD"
@ -996,8 +1042,14 @@ config LPC17_40_USBDEV_NOVBUS
---help---
Define if the hardware implementation does not support the VBUS signal
config LPC17_40_USBDEV_NOSOFTCONNECT
bool "Disable Softconnect support"
default n
---help---
Define if the hardware implementation does not support the Softconnect signal
config LPC17_40_USBDEV_NOLED
bool "Disable USB device LCD support"
bool "Disable USB device LED support"
default n
---help---
Define if the hardware implementation does not support the LED output

View File

@ -80,7 +80,7 @@ CHIP_CSRCS += lpc17_40_ethernet.c
endif
endif
ifeq ($(CONFIG_CAN),y)
ifeq ($(CONFIG_LPC17_40_CAN),y)
CHIP_CSRCS += lpc17_40_can.c
endif

View File

@ -95,6 +95,10 @@
# error "Both chrdev CAN or SocketCAN have been enabled"
#endif
#if !defined(CHRDEV_CAN) && !defined(SOCKET_CAN)
# error "No upper CAN driver enabled"
#endif
#if defined(CHRDEV_CAN)
#define lpc17_40_can_s can_dev_s
#endif

View File

@ -68,7 +68,7 @@
/* Debug ********************************************************************/
#ifdef CONFIG_DEBUG_PWM_INFO
# define pwm_dumpgpio(p,m) stm32_dumpgpio(p,m)
# define pwm_dumpgpio(p,m) lpc17_40_dumpgpio(p,m)
#else
# define pwm_dumpgpio(p,m)
#endif

View File

@ -85,7 +85,7 @@
/* Debug ********************************************************************/
#ifdef CONFIG_DEBUG_PWM_INFO
# define pwm_dumpgpio(p,m) stm32_dumpgpio(p,m)
# define pwm_dumpgpio(p,m) lpc17_40_dumpgpio(p,m)
#else
# define pwm_dumpgpio(p,m)
#endif
@ -96,16 +96,22 @@
/* This structure represents the state of one PWM timer */
struct lpc17_40_pwmchan_s
{
uint8_t channel; /* Timer output channel */
uint32_t pincfg; /* Output pin configuration */
};
struct lpc17_40_pwmtimer_s
{
const struct pwm_ops_s *ops; /* PWM operations */
uint8_t timid; /* Timer ID {0,...,7} */
uint8_t channel; /* Timer output channel: {1,..4} */
uint8_t timtype; /* See the TIMTYPE_* definitions */
uint32_t base; /* The base address of the timer */
uint32_t pincfg; /* Output pin configuration */
uint32_t pclk; /* The frequency of the peripheral clock
* that drives the timer module. */
const struct pwm_ops_s *ops; /* PWM operations */
struct lpc17_40_pwmchan_s *channels; /* Channels configuration */
uint8_t timid; /* Timer ID {0,...,7} */
uint8_t chan_num; /* Number of configured channels */
uint8_t timtype; /* See the TIMTYPE_* definitions */
uint32_t base; /* The base address of the timer */
uint32_t pclk; /* The frequency of the peripheral clock
* that drives the timer module. */
};
/****************************************************************************
@ -160,16 +166,60 @@ static const struct pwm_ops_s g_pwmops =
};
#ifdef CONFIG_LPC17_40_PWM1
static struct lpc17_40_pwmchan_s g_pwm1channels[] =
{
/* PWM1 has 6 channels */
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL1
{
.channel = 1,
.pincfg = GPIO_PWM1p1,
},
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL2
{
.channel = 2,
.pincfg = GPIO_PWM1p2,
},
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL3
{
.channel = 3,
.pincfg = GPIO_PWM1p3,
},
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL4
{
.channel = 4,
.pincfg = GPIO_PWM1p5,
},
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL5
{
.channel = 5,
.pincfg = GPIO_PWM1p5,
},
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL6
{
.channel = 6,
.pincfg = GPIO_PWM1p6,
},
#endif
};
static struct lpc17_40_pwmtimer_s g_pwm1dev =
{
.ops = &g_pwmops,
.timid = 1,
.channel = CONFIG_LPC17_40_PWM1_PIN,
.chan_num = LPC17_40_PWM1_NCHANNELS,
.channels = g_pwm1channels,
.timtype = TIMTYPE_TIM1,
.base = LPC17_40_PWM1_BASE,
.pincfg = GPIO_PWM1p1_1,
.pclk = (0x1 << 12),
};
#endif
/****************************************************************************
@ -236,27 +286,25 @@ static void pwm_dumpregs(struct lpc17_40_pwmtimer_s *priv,
const char *msg)
{
pwminfo("%s:\n", msg);
pwminfo(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n",
pwminfo(" IR: %04x TCR: %04x TC: %04x PR: %04x PC: %04x\n",
pwm_getreg(priv, LPC17_40_PWM_IR_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_TCR_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_TC_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_PR_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_PC_OFFSET));
pwminfo(" MCR: %04x\n",
pwm_getreg(priv, LPC17_40_PWM_MCR_OFFSET));
#ifdef CONFIG_PWM_MULTICHAN
pwminfo(" 0: %08x 1: %08x 2: %08x 3: %08x\n",
pwm_getreg(priv, LPC17_40_PWM_MR0_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_MR1_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_MR2_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_MR3_OFFSET));
#if defined(CONFIG_LPC17_40_PWM1)
if (priv->timtype == TIMTYPE_ADVANCED)
{
pwminfo(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n",
pwm_getreg(priv, LPC17_40_PWM_MR0_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_MR1_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_MR2_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_MR3_OFFSET));
}
else
pwminfo(" 4: %08x 5: %08x 6: %08x\n",
pwm_getreg(priv, LPC17_40_PWM_MR4_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_MR5_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_MR6_OFFSET));
#endif
{
pwminfo(" DCR: %04x DMAR: %04x\n",
pwm_getreg(priv, LPC17_40_PWM_MR2_OFFSET),
pwm_getreg(priv, LPC17_40_PWM_MR3_OFFSET));
}
}
#endif
@ -279,19 +327,116 @@ static int pwm_timer(struct lpc17_40_pwmtimer_s *priv,
const struct pwm_info_s *info)
{
irqstate_t flags;
uint32_t i;
int ret = OK;
uint32_t lerval = LER0_EN;
uint32_t pcrval = 0;
uint32_t mr0_freq;
flags = enter_critical_section();
putreg32(info->frequency, LPC17_40_PWM1_MR0); /* Set PWMMR0 = number of counts */
putreg32(info->duty, LPC17_40_PWM1_MR1); /* Set PWM cycle */
mr0_freq = 1.f / info->frequency * LPC17_40_PWM_CLOCK / 10;
putreg32(mr0_freq, LPC17_40_PWM1_MR0); /* Set PWMMR0 = number of counts */
#ifndef CONFIG_PWM_MULTICHAN
putreg32(info->duty, LPC17_40_PWM1_MR1); /* Set PWM cycle */
#else
for (i = 0; i < CONFIG_PWM_NCHANNELS; i++)
{
switch (priv->channels[i].channel)
{
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL1
case 1:
putreg32(ub16mulub16(info->channels[i].duty, mr0_freq),
LPC17_40_PWM1_MR1); /* Set PWM cycle */
break;
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL2
case 2:
putreg32(ub16mulub16(info->channels[i].duty, mr0_freq),
LPC17_40_PWM1_MR2); /* Set PWM cycle */
break;
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL3
case 3:
putreg32(ub16mulub16(info->channels[i].duty, mr0_freq),
LPC17_40_PWM1_MR3); /* Set PWM cycle */
break;
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL4
case 4:
putreg32(ub16mulub16(info->channels[i].duty, mr0_freq),
LPC17_40_PWM1_MR4); /* Set PWM cycle */
break;
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL5
case 5:
putreg32(ub16mulub16(info->channels[i].duty, mr0_freq),
LPC17_40_PWM1_MR5); /* Set PWM cycle */
break;
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL6
case 6:
putreg32(ub16mulub16(info->channels[i].duty, mr0_freq),
LPC17_40_PWM1_MR6); /* Set PWM cycle */
break;
#endif
default:
{
pwmerr("ERROR: Channel %d does not exist\n",
priv->channels[i].channel);
ret = -EINVAL;
}
}
}
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL1
pcrval |= PWMENA1;
lerval |= LER1_EN;
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL2
pcrval |= PWMENA2;
lerval |= LER2_EN;
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL3
pcrval |= PWMENA3;
lerval |= LER3_EN;
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL4
pcrval |= PWMENA4;
lerval |= LER4_EN;
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL5
pcrval |= PWMENA5;
lerval |= LER5_EN;
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL6
pcrval |= PWMENA6;
lerval |= LER6_EN;
#endif
putreg32(lerval, LPC17_40_PWM1_LER); /* Load Shadow register contents */
putreg32(pcrval, LPC17_40_PWM1_PCR); /* Enable PWM outputs */
putreg32(LER0_EN | LER3_EN, LPC17_40_PWM1_LER); /* Load Shadow register contents */
putreg32(PWMENA1, LPC17_40_PWM1_PCR); /* Enable PWM outputs */
putreg32(TCR_CNT_EN | TCR_PWM_EN, LPC17_40_PWM1_TCR); /* Enable PWM Timer */
leave_critical_section(flags);
pwm_dumpregs(priv, "After starting");
return OK;
return ret;
}
#ifdef XXXXX
@ -416,6 +561,7 @@ static int pwm_setup(struct pwm_lowerhalf_s *dev)
(struct lpc17_40_pwmtimer_s *)dev;
irqstate_t flags;
uint32_t regval;
int i;
flags = enter_critical_section();
@ -428,14 +574,17 @@ static int pwm_setup(struct pwm_lowerhalf_s *dev)
/* Select clock for the pwm peripheral */
regval = getreg32(LPC17_40_SYSCON_PCLKSEL0);
regval &= ~(0x3 << 12); /* PCLK_MC peripheral clk = CCLK = 12.5 MHz */
regval |= (0x1 << 12); /* PCLK_MC peripheral clk = CCLK = 12.5 MHz */
regval &= ~SYSCON_PCLKSEL0_PWM1_MASK; /* PCLK_MC peripheral clk = CCLK = LPC17_40_CCLK */
regval |= (SYSCON_PCLKSEL_CCLK << SYSCON_PCLKSEL0_PWM1_SHIFT); /* PCLK_MC peripheral clk = CCLK = LPC17_40_CCLK */
putreg32(regval, LPC17_40_SYSCON_PCLKSEL0);
priv->pclk = (0x1 << 12);
/* Configure the output pin */
lpc17_40_configgpio(GPIO_PWM1p1_1);
for (i = 0; i < priv->chan_num; i++)
{
lpc17_40_configgpio(priv->channels[i].pincfg);
}
putreg32(1, LPC17_40_PWM1_PR); /* Prescaler count frequency: Fpclk/1 */
putreg32(1 << 1, LPC17_40_PWM1_MCR); /* Reset on match register MR0 */
@ -465,11 +614,25 @@ static int pwm_shutdown(struct pwm_lowerhalf_s *dev)
{
struct lpc17_40_pwmtimer_s *priv =
(struct lpc17_40_pwmtimer_s *)dev;
uint32_t pincfg;
uint32_t regval;
uint32_t i;
pwminfo("TIM%d pincfg: %08x\n", priv->timid, priv->pincfg);
/* Configure the output pin to be output and low */
/* Make sure that the output has been stopped */
for (i = 0; i < priv->chan_num; i++)
{
regval = priv->channels[i].pincfg;
regval &= (GPIO_PORT_MASK | GPIO_PIN_MASK);
regval |= (GPIO_OUTPUT | GPIO_VALUE_ZERO);
lpc17_40_configgpio(regval);
}
/* Power off the pwm peripheral */
regval = getreg32(LPC17_40_SYSCON_PCONP);
regval &= ~SYSCON_PCONP_PCPWM1;
putreg32(regval, LPC17_40_SYSCON_PCONP);
return OK;
}
@ -522,7 +685,6 @@ static int pwm_stop(struct pwm_lowerhalf_s *dev)
(struct lpc17_40_pwmtimer_s *)dev;
uint32_t resetbit;
uint32_t regaddr;
uint32_t regval;
irqstate_t flags;
pwminfo("TIM%d\n", priv->timid);
@ -551,7 +713,7 @@ static int pwm_stop(struct pwm_lowerhalf_s *dev)
leave_critical_section(flags);
pwminfo("regaddr: %08x resetbit: %08x\n", regaddr, resetbit);
pwminfo("regaddr: %08lx resetbit: %08lx\n", regaddr, resetbit);
pwm_dumpregs(priv, "After stop");
return OK;
}
@ -616,19 +778,25 @@ struct pwm_lowerhalf_s *lpc17_40_pwminitialize(int timer)
switch (timer)
{
#ifdef CONFIG_LPC17_40_PWM1
case 0:
lower = &g_pwm1dev;
/* Attach but disable the TIM1 update interrupt */
break;
#endif
default:
pwmerr("ERROR: No such timer configured\n");
pwmerr("ERROR: No such timer configured or pin defined\n");
return NULL;
}
/* Ensure PWM has been shutdown */
pwm_shutdown((struct pwm_lowerhalf_s *)lower);
return (struct pwm_lowerhalf_s *)lower;
}

View File

@ -33,6 +33,57 @@
* Pre-processor Definitions
****************************************************************************/
/* PLL0CLK = CCLK * CCLK divider */
#define LPC17_40_PWM_CLOCK (LPC17_40_CCLK * BOARD_CCLKCFG_DIVIDER)
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL1
# define LPC17_40_PWM1_CHANNEL1 1
#else
#define LPC17_40_PWM1_CHANNEL1 0
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL2
#define LPC17_40_PWM1_CHANNEL2 1
#else
#define LPC17_40_PWM1_CHANNEL2 0
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL3
#define LPC17_40_PWM1_CHANNEL3 1
#else
#define LPC17_40_PWM1_CHANNEL3 0
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL4
#define LPC17_40_PWM1_CHANNEL4 1
#else
#define LPC17_40_PWM1_CHANNEL4 0
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL5
#define LPC17_40_PWM1_CHANNEL5 1
#else
#define LPC17_40_PWM1_CHANNEL5 0
#endif
#ifdef CONFIG_LPC17_40_PWM1_CHANNEL6
#define LPC17_40_PWM1_CHANNEL6 1
#else
#define LPC17_40_PWM1_CHANNEL6 0
#endif
#define LPC17_40_PWM1_NCHANNELS (LPC17_40_PWM1_CHANNEL1 + \
LPC17_40_PWM1_CHANNEL2 + \
LPC17_40_PWM1_CHANNEL3 + \
LPC17_40_PWM1_CHANNEL4 + \
LPC17_40_PWM1_CHANNEL5 + \
LPC17_40_PWM1_CHANNEL6)
#if CONFIG_PWM_NCHANNELS > LPC17_40_PWM1_NCHANNELS
# error "PWM subystem has more channels then physical channels enabled"
#endif
/****************************************************************************
* Public Types
****************************************************************************/

View File

@ -68,7 +68,7 @@
/* Debug ********************************************************************/
#ifdef CONFIG_DEBUG_PWM_INFO
# define pwm_dumpgpio(p,m) stm32_dumpgpio(p,m)
# define pwm_dumpgpio(p,m) lpc17_40_dumpgpio(p,m)
#else
# define pwm_dumpgpio(p,m)
#endif
@ -220,25 +220,25 @@ static void timer_dumpregs(struct lpc17_40_timer_s *priv,
{
pwminfo("%s:\n", msg);
pwminfo(" CR1: %04x CR2: %04x SMCR: %04x DIER: %04x\n",
timer_getreg(priv, LPC17_40_PWM_MR0_OFFSET),
timer_getreg(priv, LPC17_40_PWM_MR1_OFFSET),
timer_getreg(priv, LPC17_40_PWM_MR2_OFFSET),
timer_getreg(priv, LPC17_40_PWM_MR3_OFFSET));
timer_getreg(priv, LPC17_40_TMR_MR0_OFFSET),
timer_getreg(priv, LPC17_40_TMR_MR1_OFFSET),
timer_getreg(priv, LPC17_40_TMR_MR2_OFFSET),
timer_getreg(priv, LPC17_40_TMR_MR3_OFFSET));
#if defined(CONFIG_LPC17_40_TMR0)
if (priv->timtype == TIMTYPE_ADVANCED)
{
pwminfo(" RCR: %04x BDTR: %04x DCR: %04x DMAR: %04x\n",
timer_getreg(priv, LPC17_40_PWM_MR0_OFFSET),
timer_getreg(priv, LPC17_40_PWM_MR1_OFFSET),
timer_getreg(priv, LPC17_40_PWM_MR2_OFFSET),
timer_getreg(priv, LPC17_40_PWM_MR3_OFFSET));
timer_getreg(priv, LPC17_40_TMR_MR0_OFFSET),
timer_getreg(priv, LPC17_40_TMR_MR1_OFFSET),
timer_getreg(priv, LPC17_40_TMR_MR2_OFFSET),
timer_getreg(priv, LPC17_40_TMR_MR3_OFFSET));
}
else
#endif
{
pwminfo(" DCR: %04x DMAR: %04x\n",
timer_getreg(priv, LPC17_40_PWM_MR2_OFFSET),
timer_getreg(priv, LPC17_40_PWM_MR3_OFFSET));
timer_getreg(priv, LPC17_40_TMR_MR2_OFFSET),
timer_getreg(priv, LPC17_40_TMR_MR3_OFFSET));
}
}
#endif

View File

@ -3357,7 +3357,9 @@ void arm_usbinitialize(void)
#ifndef CONFIG_LPC17_40_USBDEV_NOVBUS
lpc17_40_configgpio(GPIO_USB_VBUS); /* VBUS status input */
#endif
#ifndef CONFIG_LPC17_40_USBDEV_NOSOFTCONNECT
lpc17_40_configgpio(GPIO_USB_CONNECT); /* SoftConnect control signal */
#endif
#ifndef CONFIG_LPC17_40_USBDEV_NOLED
lpc17_40_configgpio(GPIO_USB_UPLED); /* GoodLink LED control signal */
#endif

View File

@ -25,6 +25,7 @@ CONFIG_BOARDCTL_RESET=y
CONFIG_BOARD_LOOPSPERMSEC=11934
CONFIG_BOOT_RUNFROMSDRAM=y
CONFIG_BUILTIN=y
CONFIG_CAN=y
CONFIG_CANCELLATION_POINTS=y
CONFIG_CANUTILS_CANLIB=y
CONFIG_CAN_EXTID=y