Merge pull request #236 from alexclewontin/pwm-fix

[NUC123SD4AN0] Barebones PWM module for downstream compatibility
This commit is contained in:
Fabien Poussin 2020-12-11 10:26:57 +01:00 committed by GitHub
commit 7d6e9b8f23
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 1533 additions and 225 deletions

View File

@ -16,7 +16,9 @@
#include "hal.h"
#if HAL_USE_PAL
const PALConfig pal_default_config;
#endif
/**
* @brief Board-specific initialization code.

View File

@ -27,7 +27,6 @@
#define NUC123SD4AN0
#define BOARD_NAME "NUTINY SDK NUC123 V2.0"
#define NUC123_LSE_BYPASS TRUE
/*
* Board specific settings.

View File

@ -4,9 +4,5 @@ BOARDSRC = $(CHIBIOS_CONTRIB)/os/hal/boards/NUTINY-SDK-NUC123-V2.0/board.c
# Required include directories
BOARDINC = $(CHIBIOS_CONTRIB)/os/hal/boards/NUTINY-SDK-NUC123-V2.0
# Define linker script file here, as the linker script is per chip variant, which should
# remain constant per board
LDSCRIPT = $(STARTUPLD_CONTRIB)/NUC123SD4AN0.ld
ALLCSRC += $(BOARDSRC)
ALLINC += $(BOARDINC)

View File

@ -1,10 +1,9 @@
ifeq ($(USE_SMART_BUILD),yes)
ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),)
PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/GPIOv1/hal_pal_lld.c
PLATFORMINC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/GPIOv1
endif
else
PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/GPIOv1/hal_pal_lld.c
endif
# ifeq ($(USE_SMART_BUILD),yes)
# ifneq ($(findstring HAL_USE_PAL TRUE,$(HALCONF)),)
# PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/GPIOv1/hal_pal_lld.c
# endif
# else
# PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/GPIOv1/hal_pal_lld.c
# endif
PLATFORMINC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/GPIOv1

View File

@ -1,4 +1,10 @@
PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/hal_st_lld.c
ifeq ($(USE_SMART_BUILD),yes)
ifneq ($(findstring HAL_USE_PWM TRUE,$(HALCONF)),)
PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/hal_pwm_lld.c
#PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/timer.c
endif
else
PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/hal_pwm_lld.c
endif
PLATFORMSRC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1/hal_st_lld.c
PLATFORMINC += $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/LLD/TIMv1

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2019 /u/KeepItUnder
Copyright (C) 2020 Alex Lewontin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -30,22 +30,124 @@
/* Driver local definitions. */
/*===========================================================================*/
#define NUC123_PWM_CLKSRC_HSE 0x0UL
#define NUC123_PWM_CLKSRC_HCLK 0x2UL
#define NUC123_PWM_CLKSRC_HSI 0x3UL
#define NUC123_PWM_CLKSRC_LSI 0x7UL
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief PWMD1 driver identifier.
*/
#if (NUC123_PWM_USE_PWM1 == TRUE) || defined(__DOXYGEN__)
PWMDriver PWMD1;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
typedef struct {
__IO uint32_t CNR; /* Offset: 0x0C PWM Counter Register 0 */
__IO uint32_t CMR; /* Offset: 0x10 PWM Comparator Register 0 */
__I uint32_t PDR; /* Offset: 0x14 PWM Data Register 0 */
} PWM_CHANNEL_T;
#define PWMA_CHANNELS_BASE (PWMA_BASE + 0xC)
#define PWMA_CHANNELS ((PWM_CHANNEL_T *) PWMA_CHANNELS_BASE)
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Shared IRQ handler.
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
*
* @param[in] pwmd pointer to a @p PWMDriver object
*
* @notapi
*/
static void pwm_lld_serve_interrupt(PWMDriver *pwmp) {
uint32_t piir;
uint32_t pier_clr_msk;
uint32_t poe_clr_msk;
pier_clr_msk = 0;
poe_clr_msk = 0;
piir = PWMA->PIIR;
PWMA->PIIR = piir;
if (piir & PWM_PIIR_PWMDIF0_Msk) {
pwmp->config->channels[0].callback(pwmp);
}
if (piir & PWM_PIIR_PWMDIF1_Msk) {
pwmp->config->channels[1].callback(pwmp);
}
if (piir & PWM_PIIR_PWMDIF2_Msk) {
pwmp->config->channels[2].callback(pwmp);
}
if (piir & PWM_PIIR_PWMDIF3_Msk) {
pwmp->config->channels[3].callback(pwmp);
}
if (piir & PWM_PIIR_PWMIF0_Msk) {
if (pwmp->periodic_callback_enabled) {
pwmp->config->callback(pwmp);
}
if (!pwmIsChannelEnabledI(pwmp, 0)) {
poe_clr_msk |= PWM_POE_PWM1_Msk;
pier_clr_msk |= PWM_PIER_PWMDIE0_Msk;
}
}
if (piir & PWM_PIIR_PWMIF1_Msk) {
poe_clr_msk |= PWM_POE_PWM1_Msk;
pier_clr_msk |= PWM_PIER_PWMDIE1_Msk;
pier_clr_msk |= PWM_PIER_PWMIE1_Msk;
}
if (piir & PWM_PIIR_PWMIF2_Msk) {
poe_clr_msk |= PWM_POE_PWM2_Msk;
pier_clr_msk |= PWM_PIER_PWMDIE2_Msk;
pier_clr_msk |= PWM_PIER_PWMIE2_Msk;
}
if (piir & PWM_PIIR_PWMIF3_Msk) {
poe_clr_msk |= PWM_POE_PWM3_Msk;
pier_clr_msk |= PWM_PIER_PWMDIE3_Msk;
pier_clr_msk |= PWM_PIER_PWMIE3_Msk;
}
PWMA->POE &= ~poe_clr_msk;
PWMA->PIER &= ~pier_clr_msk;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief PWM interrupt handler.
*
* @isr
*/
OSAL_IRQ_HANDLER(NUC123_PWMA_HANDLER)
{
OSAL_IRQ_PROLOGUE();
pwm_lld_serve_interrupt(&PWMD1);
OSAL_IRQ_EPILOGUE();
}
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
@ -55,175 +157,277 @@
*
* @notapi
*/
// void pwm_lld_init(void) {
// }
void pwm_lld_start(PWM_T *pwm, uint32_t mask) {
uint32_t pwmStart = 0;
for(uint32_t i = 0; i < PWM_CHANNELS; i++) {
if (mask & (1 << i)) {
pwmStart |= (PWM_PCR_CH0EN_Msk << (i * 8));
}
}
(pwm)->PCR |= pwmStart;
}
void pwm_lld_enable_period_int(PWM_T *pwm, uint32_t pwmChannel, uint32_t periodType) {
(pwm)->PIER = ((pwm)->PIER & ~(0x01ul << (pwmChannel >> 1))) | (0x01ul << pwmChannel) | (periodType << (pwmChannel >> 1));
}
void pwm_lld_disable_period_int(PWM_T *pwm, uint32_t pwmChannel) {
(pwm)->PIER &= ~(PWM_PIER_PWMIE0_Msk << pwmChannel);
}
uint32_t pwm_lld_get_period_int(PWM_T *pwm, uint32_t pwmChannel) {
if ((pwm)->PIIR & (0x01ul << (pwmChannel))) {
return 1;
} else {
return 0;
}
}
void pwm_lld_clear_period_int(PWM_T *pwm, uint32_t pwmChannel) {
(pwm)->PIIR = (0x01ul << pwmChannel);
}
uint32_t pwm_lld_config_output_channel(PWM_T *pwm, uint32_t channel, uint32_t freq, uint32_t duty)
void pwm_lld_init(void)
{
uint32_t regSource;
uint32_t clkSource;
uint32_t pwmClk;
uint8_t divider = 1;
uint8_t prescale = 0xFF;
uint16_t CNR = 0xFFFF;
if (channel < 2) {
regSource = ((CLK->CLKSEL2 & (CLK_CLKSEL2_PWM01_S_Msk)) >> (CLK_CLKSEL2_PWM01_S_Pos - 2)) | (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM01_S_Msk)) >> (CLK_CLKSEL1_PWM01_S_Pos);
} else {
regSource = ((CLK->CLKSEL2 & (CLK_CLKSEL2_PWM23_S_Msk)) >> (CLK_CLKSEL2_PWM23_S_Pos - 2)) | (CLK->CLKSEL1 & (CLK_CLKSEL1_PWM23_S_Msk)) >> (CLK_CLKSEL1_PWM23_S_Pos);
}
#if (NUC123_PWM_USE_PWM1 == TRUE)
/* Driver initialization.*/
pwmObjectInit(&PWMD1);
PWMD1.channels = PWM_CHANNELS;
#endif
}
if (regSource == 2) {
SystemCoreClockUpdate();
clkSource = SystemCoreClock;
} else {
switch (regSource) {
case 0:
clkSource = __HXT;
break;
case 1:
case 4:
case 5:
case 6:
clkSource = 0;
break;
case 2:
SystemCoreClockUpdate();
clkSource = SystemCoreClock;
break;
case 3:
clkSource = __HIRC;
break;
case 7:
clkSource = __LIRC;
break;
/**
* @brief Configures and activates the PWM peripheral.
* @note Starting a driver that is already in the @p PWM_READY state
* disables all the active channels.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_start(PWMDriver *pwmp)
{
uint32_t clksel1;
uint32_t clksel2;
uint32_t prescale;
uint32_t pcr;
if (pwmp->state == PWM_STOP) {
clksel1 = CLK->CLKSEL1;
clksel2 = CLK->CLKSEL2;
clksel1 = (clksel1 & ~(CLK_CLKSEL1_PWM01_S_Msk)) |
((NUC123_PWM_CLKSRC_HCLK << CLK_CLKSEL1_PWM01_S_Pos) &
CLK_CLKSEL1_PWM01_S_Msk);
clksel1 = (clksel1 & ~(CLK_CLKSEL1_PWM23_S_Msk)) |
((NUC123_PWM_CLKSRC_HCLK << CLK_CLKSEL1_PWM23_S_Pos) &
CLK_CLKSEL1_PWM23_S_Msk);
clksel2 = (clksel2 & ~(CLK_CLKSEL2_PWM01_S_E_Msk)) |
((NUC123_PWM_CLKSRC_HCLK >> 2) << CLK_CLKSEL2_PWM01_S_E_Pos);
clksel2 = (clksel2 & ~(CLK_CLKSEL2_PWM23_S_E_Msk)) |
((NUC123_PWM_CLKSRC_HCLK >> 2) << CLK_CLKSEL2_PWM23_S_E_Pos);
CLK->CLKSEL1 = clksel1;
CLK->CLKSEL2 = clksel2;
CLK->APBCLK |= (CLK_APBCLK_PWM01_EN_Msk | CLK_APBCLK_PWM23_EN_Msk);
nvicEnableVector(NUC123_PWMA_NUMBER, NUC123_PWM_IRQ_PRIORITY);
SYS->IPRSTC2 |= SYS_IPRSTC2_PWM03_RST_Msk;
SYS->IPRSTC2 &= ~(SYS_IPRSTC2_PWM03_RST_Msk);
/* Set clock scaling to 1 */
PWMA->CSR = (4 << PWM_CSR_CSR0_Pos) | (4 << PWM_CSR_CSR1_Pos) |
(4 << PWM_CSR_CSR2_Pos) | (4 << PWM_CSR_CSR3_Pos);
/* Set prescale to set frequency */
prescale = NUC123_HCLK / pwmp->config->frequency;
PWMA->PPR = (PWMA->PPR & ~(PWM_PPR_CP01_Msk | PWM_PPR_CP23_Msk)) |
((prescale << PWM_PPR_CP01_Pos) & PWM_PPR_CP01_Msk) |
((prescale << PWM_PPR_CP23_Pos) & PWM_PPR_CP23_Msk);
/*
* PINV == 0 -> active high, PINV == 1 -> active low.
* CHnINV vs CHnPINV:
* - CHnINV inverts before deadzone generation
* - CHnPINV inverts after deadzone generation
* If no deadzone generation, INV(signal) == PINV(signal) and signal == INV(PINV(signal))
* If there is deadzone generation, things get more complicated.
*/
pcr = PWMA->PCR;
pcr &= ~(PWM_PCR_CH0PINV_Msk | PWM_PCR_CH0INV_Msk);
pcr &= ~(PWM_PCR_CH1PINV_Msk | PWM_PCR_CH1INV_Msk);
pcr &= ~(PWM_PCR_CH2PINV_Msk | PWM_PCR_CH2INV_Msk);
pcr &= ~(PWM_PCR_CH3PINV_Msk | PWM_PCR_CH3INV_Msk);
/* Conditionally (and branchlessly) set the bits for the inverted channels */
pcr |= ((pwmp->config->channels[0].mode == PWM_OUTPUT_ACTIVE_LOW) * PWM_PCR_CH0PINV_Msk);
pcr |= ((pwmp->config->channels[1].mode == PWM_OUTPUT_ACTIVE_LOW) * PWM_PCR_CH1PINV_Msk);
pcr |= ((pwmp->config->channels[2].mode == PWM_OUTPUT_ACTIVE_LOW) * PWM_PCR_CH2PINV_Msk);
pcr |= ((pwmp->config->channels[3].mode == PWM_OUTPUT_ACTIVE_LOW) * PWM_PCR_CH3PINV_Msk);
/* Set to auto-reload (this will also reset CMR & CNR) */
pcr |= (PWM_PCR_CH0MOD_Msk | PWM_PCR_CH1MOD_Msk);
pcr |= (PWM_PCR_CH2MOD_Msk | PWM_PCR_CH3MOD_Msk);
PWMA->PCR = pcr;
/* TODO: Deadzone generation */
/* Mux the pins per the channel configs */
if (pwmp->config->channels[0].mode != PWM_OUTPUT_DISABLED) {
if (pwmp->config->channels[0].pinmask & NUC123_PWM_CH0_PIN_PA12) {
SYS->GPA_MFP |= (1 << 12);
}
}
/* Calculate best divider */
while (divider < 17) {
pwmClk = (clkSource / (freq)) / divider;
// If pwmClk is larger than (CNR * prescale) then divider can still be bigger
if (pwmClk > (0x10000 * 0x100)) {
continue;
}
// Set prescaler to CNR value lower than 0xFFFF
prescale = (pwmClk + 0xFFFF) / 0x10000;
// Keep prescale bigger than 2 this loop
if (prescale < 3) {
prescale = 2;
}
pwmClk /= prescale;
if (pwmClk <= 0x10000) {
if (pwmClk == 1) {
CNR = 1; // Too fast, and PWM cannot generate expected frequency...
} else {
CNR = pwmClk;
}
break;
}
divider = divider << 1;
if (pwmp->config->channels[1].mode != PWM_OUTPUT_DISABLED) {
if (pwmp->config->channels[1].pinmask & NUC123_PWM_CH1_PIN_PA13) {
SYS->GPA_MFP |= (1 << 13);
}
}
pwmClk = clkSource / (prescale * divider * CNR);
if (pwmp->config->channels[2].mode != PWM_OUTPUT_DISABLED) {
if (pwmp->config->channels[2].pinmask & NUC123_PWM_CH2_PIN_PA14) {
SYS->GPA_MFP |= (1 << 14);
}
/* Calculate PWM Registers */
prescale -= 1;
CNR -= 1;
/* Set final divider for output calculation */
switch (divider) {
case 1:
divider = 4;
break;
case 4:
divider = 1;
break;
case 8:
divider = 2;
break;
case 16:
divider = 3;
break;
case 0:
case 2:
case 3:
case 5:
case 6:
case 7:
case 9:
case 10:
case 11:
case 12:
case 13:
case 14:
case 15:
default:
divider = 0;
break;
if (pwmp->config->channels[2].pinmask & NUC123_PWM_CH2_PIN_PC12) {
SYS->GPC_MFP |= (1 << 12);
SYS->ALT_MFP |= SYS_ALT_MFP_PC12_MFP1_Msk;
}
}
// Prescaler is shared every two channels (01/23/etc.)
(pwm)->PPR = ((pwm)->PPR & ~(PWM_PPR_CP01_Msk << ((channel >> 1) * 8))) | (prescale << ((channel >> 1) * 8));
(pwm)->CSR = ((pwm)->CSR & ~(PWM_CSR_CSR0_Msk << (4 * channel))) | (divider << (4 * channel));
if (pwmp->config->channels[3].mode != PWM_OUTPUT_DISABLED) {
if (pwmp->config->channels[3].pinmask & NUC123_PWM_CH3_PIN_PA15) {
SYS->GPA_MFP |= (1 << 15);
SYS->ALT_MFP &= ~SYS_ALT_MFP_PA15_MFP1_Msk;
}
// Set edge-aligned PWM
(pwm)->PCR &= ~(PWM_PCR_PWM01TYPE_Msk << (channel >> 1));
(pwm)->PCR |= PWM_PCR_CH0MOD_Msk << (8 * channel);
// Set PWM register values
if (duty) {
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CMR0)) + channel * 12))) = duty * (CNR + 1) / 100 - 1;
} else {
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CMR0)) + channel * 12))) = 0;
if (pwmp->config->channels[3].pinmask & NUC123_PWM_CH3_PIN_PC13) {
SYS->GPC_MFP |= (1 << 13);
SYS->ALT_MFP |= SYS_ALT_MFP_PC13_MFP1_Msk;
}
}
*((__IO uint32_t *)((((uint32_t) & ((pwm)->CNR0)) + channel * 12))) = CNR;
#if defined(NUC123xxxAEx)
/* TODO: Implement PWM0 PC8 & PWM1 PB9 */
#endif
return(pwmClk);
PWMA->PIER &= ~(PWM_PIER_INT01TYPE_Msk | PWM_PIER_INT23TYPE_Msk);
pwm_lld_change_period(pwmp, pwmp->config->period);
PWMA->PCR |= (PWM_PCR_CH0EN_Msk | PWM_PCR_CH1EN_Msk |
PWM_PCR_CH2EN_Msk | PWM_PCR_CH3EN_Msk);
}
}
/**
* @brief Deactivates the PWM peripheral.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_stop(PWMDriver *pwmp)
{
/* If in ready state then disables the PWM clock.*/
if (pwmp->state == PWM_READY) {
#if NUC123_PWM_USE_PWM1 == TRUE
if (&PWMD1 == pwmp) {
CLK->APBCLK &= ~(CLK_APBCLK_PWM01_EN_Msk | CLK_APBCLK_PWM23_EN_Msk);
nvicDisableVector(NUC123_PWMA_NUMBER);
return;
}
#endif
}
}
/**
* @brief Enables a PWM channel.
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The channel is active using the specified configuration.
* @note The function has effect at the next cycle start.
* @note Channel notification is not enabled.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...channels-1)
* @param[in] width PWM pulse width as clock pulses number
*
* @notapi
*/
void pwm_lld_enable_channel(PWMDriver *pwmp, pwmchannel_t channel,
pwmcnt_t width)
{
(void)pwmp;
PWMA_CHANNELS[channel].CMR = width;
PWMA->POE |= PWM_POE_PWM0_Msk << channel;
}
/**
* @brief Disables a PWM channel and its notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The channel is disabled and its output line returned to the
* idle state.
* @note The function has effect at the next cycle start.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...channels-1)
*
* @notapi
*/
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel)
{
(void)pwmp;
/* We do not disable immediately, but enable the periodic interrupt
We will actually disable in the next ISR. */
PWMA->PIER |= (PWM_PIER_PWMIE0_Msk << channel);
}
/**
* @brief Enables the periodic activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @note If the notification is already enabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_enable_periodic_notification(PWMDriver *pwmp) {
(void)pwmp;
PWMA->PIER |= PWM_PIER_PWMIE0_Msk;
}
/**
* @brief Disables the periodic activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @note If the notification is already disabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_disable_periodic_notification(PWMDriver *pwmp) {
(void)pwmp;
/* TODO: Make sure this isn't in use for disabling the periodic channel */
PWMA->PIER &= ~PWM_PIER_PWMIE0_Msk;
}
/**
* @brief Enables a channel de-activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @pre The channel must have been activated using @p pwmEnableChannel().
* @note If the notification is already enabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...channels-1)
*
* @notapi
*/
void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel)
{
(void)pwmp;
PWMA->PIER |= (PWM_PIER_PWMDIE0_Msk << channel);
}
/**
* @brief Disables a channel de-activation edge notification.
* @pre The PWM unit must have been activated using @p pwmStart().
* @pre The channel must have been activated using @p pwmEnableChannel().
* @note If the notification is already disabled then the call has no effect.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...channels-1)
*
* @notapi
*/
void pwm_lld_disable_channel_notification(PWMDriver * pwmp,
pwmchannel_t channel)
{
(void)pwmp;
PWMA->PIER &= ~(PWM_PIER_PWMDIE0_Msk << channel);
}
void _pwm_lld_change_period(PWMDriver *pwmp, pwmcnt_t period) {
(void)pwmp;
osalSysLock();
PWMA_CHANNELS[0].CNR = period - 1;
PWMA_CHANNELS[1].CNR = period - 1;
PWMA_CHANNELS[2].CNR = period - 1;
PWMA_CHANNELS[3].CNR = period - 1;
osalSysUnlock();
}
#endif /* HAL_USE_PWM */

View File

@ -1,5 +1,5 @@
/*
Copyright (C) 2019 /u/KeepItUnder
Copyright (C) 2020 Alex Lewontin
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -25,9 +25,7 @@
#ifndef HAL_PWM_LLD_H
#define HAL_PWM_LLD_H
// #if HAL_USE_PWM || defined(__DOXYGEN__)
// #include "stm32_tim.h"
#if (HAL_USE_PWM == TRUE) || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
@ -36,84 +34,237 @@
/**
* @brief Number of PWM channels per PWM driver.
*/
#define PWM_CHANNELS (4)
#define PWM_CHANNELS 4
#define PWM_CH0 0x0ul
#define PWM_CH1 0x1ul
#define PWM_CH2 0x2ul
#define PWM_CH3 0x3ul
/**
* @brief Possible per-channel output pin mask values.
* @{
*/
/**
* @brief Channel 0 output pin mask values.
* @note Pin PA.12 has not yet been implemented
*/
#define NUC123_PWM_CH0_PIN_NONE 0x0
#define NUC123_PWM_CH0_PIN_PA12 0x1
#if defined(NUC123xxxAEx)
#define NUC123_PWM_CH0_PIN_PC8 0x2
#endif
#define PWM_EDGE_ALIGNED (0x0ul) /*!< Edge aligned */
#define PWM_CENTER_ALIGNED (0x01ul) /*!< Center aligned */
/**
* @brief Channel 1 output pin mask values.
* @note Pin PB.9 has not yet been implemented
*/
#define NUC123_PWM_CH1_PIN_NONE 0x0
#define NUC123_PWM_CH1_PIN_PA13 0x1
#if defined(NUC123xxxAEx)
#define NUC123_PWM_CH1_PIN_PB9 0x2
#endif
#define PWM_CLK_DIV_1 (0x04ul) /*!< Divide by 1 */
#define PWM_CLK_DIV_2 (0x0ul) /*!< Divide by 2 */
#define PWM_CLK_DIV_4 (0x01ul) /*!< Divide by 4 */
#define PWM_CLK_DIV_8 (0x02ul) /*!< Divide by 8 */
#define PWM_CLK_DIV_16 (0x03ul) /*!< Divide by 16 */
#define PWM_PERIOD_INT_UNDERFLOW (0) /*!< Period interrupt - counter underflow */
#define PWM_PERIOD_INT_MATCH_CNR (PWM_PIER_INT01TYPE_Msk) /*!< Period interrupt - counter matches CNR */
#define PWM_CAPTURE_INT_RISING_LATCH (PWM_CCR0_CRL_IE0_Msk) /*!< Capture interrupt - rising latch */
#define PWM_CAPTURE_INT_FALLING_LATCH (PWM_CCR0_CFL_IE0_Msk) /*!< Capture interrupt - falling latch */
/**
* @brief Channel 2 output pin mask values.
*/
#define NUC123_PWM_CH2_PIN_NONE 0x0
#define NUC123_PWM_CH2_PIN_PA14 0x1
#define NUC123_PWM_CH2_PIN_PC12 0x2
/**
* @brief Channel 3 output pin mask values.
*/
#define NUC123_PWM_CH3_PIN_NONE 0x0
#define NUC123_PWM_CH3_PIN_PA15 0x1
#define NUC123_PWM_CH3_PIN_PC13 0x2
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name NUC123 configuration options
* @{
*/
/**
* @brief PWMD1 driver enable switch.
* @details If set to @p TRUE the support for PWM1 is included.
* @note The default is @p TRUE
*/
#if !defined(NUC123_PWM_USE_PWM1) || defined(__DOXYGEN__)
#define NUC123_PWM_USE_PWM1 TRUE
#endif
/**
* @brief PWMD1 driver IRQ priority.
*/
#if !defined(NUC123_PWM_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define NUC123_PWM_IRQ_PRIORITY 3
#endif
/** @} */
/*===========================================================================*/
/* Configuration checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a PWM mode.
*/
typedef uint32_t pwmmode_t;
/**
* @brief Type of a PWM channel.
*/
typedef uint8_t pwmchannel_t;
/**
* @brief Type of a channels mask.
*/
typedef uint8_t pwmchnmsk_t;
/**
* @brief Type of a PWM counter.
*/
typedef uint32_t pwmcnt_t;
/**
* @brief Type of a PWM driver channel configuration structure.
*/
typedef struct {
/**
* @brief Channel active logic level.
*/
pwmmode_t mode;
/**
* @brief Channel callback pointer.
* @note This callback is invoked on the channel compare event. If set to
* @p NULL then the callback is disabled.
*/
pwmcallback_t callback;
/* End of the mandatory fields.*/
/**
* @brief A mask of pins the PWM signal will be output on.
* @note See driver constants for possible values.
*/
uint8_t pinmask;
} PWMChannelConfig;
/**
* @brief Type of a PWM driver configuration structure.
*/
typedef struct {
/**
* @brief Timer clock in Hz.
* @note The low level can use assertions in order to catch invalid
* frequency specifications.
*/
uint32_t frequency;
/**
* @brief PWM period in ticks.
* @note The low level can use assertions in order to catch invalid
* period specifications.
*/
pwmcnt_t period;
/**
* @brief Periodic callback pointer.
* @note This callback is invoked on PWM counter reset. If set to
* @p NULL then the callback is disabled.
*/
pwmcallback_t callback;
/**
* @brief Channels configurations.
*/
PWMChannelConfig channels[PWM_CHANNELS];
/* End of the mandatory fields.*/
} PWMConfig;
/**
* @brief Structure representing a PWM driver.
*/
struct PWMDriver {
/**
* @brief Driver state.
*/
pwmstate_t state;
/**
* @brief Current driver configuration data.
*/
const PWMConfig *config;
/**
* @brief Current PWM period in ticks.
*/
pwmcnt_t period;
/**
* @brief Mask of the enabled channels.
*/
pwmchnmsk_t enabled;
/**
* @brief Number of channels in this instance.
*/
pwmchannel_t channels;
#if defined(PWM_DRIVER_EXT_FIELDS)
PWM_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
_Bool periodic_callback_enabled;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Changes the period the PWM peripheral.
* @details This function changes the period of a PWM unit that has already
* been activated using @p pwmStart().
* @pre The PWM unit must have been activated using @p pwmStart().
* @post The PWM unit period is changed to the new value.
* @note The function has effect at the next cycle start.
* @note If a period is specified that is shorter than the pulse width
* programmed in one of the channels then the behavior is not
* guaranteed.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] period new cycle time in ticks
*
* @notapi
*/
#define pwm_lld_change_period(pwmp, period) _pwm_lld_change_period(pwmp, period)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if (NUC123_PWM_USE_PWM1 == TRUE) && !defined(__DOXYGEN__)
extern PWMDriver PWMD1;
#endif
#ifdef __cplusplus
extern "C" {
#endif
// void pwm_lld_init(void);
// void pwm_lld_start(PWMDriver *pwmp);
// void pwm_lld_stop(PWMDriver *pwmp);
// void pwm_lld_enable_channel(PWMDriver *pwmp,
// pwmchannel_t channel,
// pwmcnt_t width);
// void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel);
// void pwm_lld_enable_periodic_notification(PWMDriver *pwmp);
// void pwm_lld_disable_periodic_notification(PWMDriver *pwmp);
// void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
// pwmchannel_t channel);
// void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
// pwmchannel_t channel);
// void pwm_lld_serve_interrupt(PWMDriver *pwmp);
void pwm_lld_enable_period_int(PWM_T *pwm, uint32_t pwmChannel, uint32_t periodType);
void pwm_lld_disable_period_int(PWM_T *pwm, uint32_t pwmChannel);
void pwm_lld_start(PWM_T *pwm, uint32_t mask);
void pwm_lld_clear_period_int(PWM_T *pwm, uint32_t pwmChannel);
uint32_t pwm_lld_get_period_int(PWM_T *pwm, uint32_t pwmChannel);
uint32_t pwm_lld_config_output_channel(PWM_T *pwm, uint32_t channel, uint32_t freq, uint32_t duty);
void pwm_lld_init(void);
void pwm_lld_start(PWMDriver *pwmp);
void pwm_lld_stop(PWMDriver *pwmp);
void pwm_lld_enable_channel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width);
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel);
void pwm_lld_enable_periodic_notification(PWMDriver *pwmp);
void pwm_lld_disable_periodic_notification(PWMDriver *pwmp);
void pwm_lld_enable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel);
void pwm_lld_disable_channel_notification(PWMDriver *pwmp,
pwmchannel_t channel);
void _pwm_lld_change_period(PWMDriver *pwmp, pwmcnt_t period);
#ifdef __cplusplus
}
#endif
// #endif /* HAL_USE_PWM */
#endif /* HAL_USE_PWM */
#endif /* HAL_PWM_LLD_H */

View File

@ -8,8 +8,7 @@ PLATFORMINC := $(CHIBIOS)/os/hal/ports/common/ARMCMx \
# Optional platform files.
ifeq ($(USE_SMART_BUILD),yes)
HALCONF := $(strip $(shell cat halconf.h | egrep -e "\#define"))
HALCONF := $(strip $(shell cat $(CONFDIR)/halconf.h $(CONFDIR)/halconf_community.h | egrep -e "\#define"))
endif
# Drivers compatible with the platform.

View File

@ -115,6 +115,9 @@ include $(CHIBIOS)/tools/mk/autobuild.mk
#include $(CHIBIOS)/test/rt/rt_test.mk
#include $(CHIBIOS)/test/oslib/oslib_test.mk
# Define linker script file here
LDSCRIPT= $(STARTUPLD_CONTRIB)/NUC123SD4AN0.ld
# C sources that can be compiled in ARM or THUMB mode depending on the global
# setting.
CSRC = $(ALLCSRC) \
@ -183,7 +186,6 @@ include $(RULESPATH)/rules.mk
# Custom rules
#
OPENOCD:=$(shell readlink -f `which openocd`)
OPENOCDPATH:=$(shell dirname $(OPENOCD))/../share/openocd
@ -195,11 +197,3 @@ connect:
flash: $(BUILDDIR)/$(PROJECT).elf
openocd -f ../scripts/interface/nulink.cfg -f ../scripts/target/numicroM0.cfg -c "program $< verify reset exit"
#
# Custom rules
##############################################################################

View File

@ -0,0 +1,203 @@
##############################################################################
# Build global options
# NOTE: Can be overridden externally.
#
# Compiler options here.
ifeq ($(USE_OPT),)
USE_OPT = -ggdb -g3 -gdwarf-3 -gstrict-dwarf -fomit-frame-pointer -falign-functions=16
endif
# C specific options here (added to USE_OPT).
ifeq ($(USE_COPT),)
USE_COPT =
endif
# C++ specific options here (added to USE_OPT).
ifeq ($(USE_CPPOPT),)
USE_CPPOPT = -fno-rtti
endif
# Enable this if you want the linker to remove unused code and data.
ifeq ($(USE_LINK_GC),)
USE_LINK_GC = yes
endif
# Linker extra options here.
ifeq ($(USE_LDOPT),)
USE_LDOPT =
endif
# Enable this if you want link time optimizations (LTO).
ifeq ($(USE_LTO),)
USE_LTO = yes
endif
# Enable this if you want to see the full log while compiling.
ifeq ($(USE_VERBOSE_COMPILE),)
USE_VERBOSE_COMPILE = no
endif
# If enabled, this option makes the build process faster by not compiling
# modules not used in the current configuration.
ifeq ($(USE_SMART_BUILD),)
USE_SMART_BUILD = yes
endif
#
# Build global options
##############################################################################
##############################################################################
# Architecture or project specific options
#
# Stack size to be allocated to the Cortex-M process stack. This stack is
# the stack used by the main() thread.
ifeq ($(USE_PROCESS_STACKSIZE),)
USE_PROCESS_STACKSIZE = 0x400
endif
# Stack size to the allocated to the Cortex-M main/exceptions stack. This
# stack is used for processing interrupts and exceptions.
ifeq ($(USE_EXCEPTIONS_STACKSIZE),)
USE_EXCEPTIONS_STACKSIZE = 0x400
endif
# Enables the use of FPU (no, softfp, hard).
ifeq ($(USE_FPU),)
USE_FPU = no
endif
# FPU-related options.
ifeq ($(USE_FPU_OPT),)
USE_FPU_OPT = -mfloat-abi=$(USE_FPU) -mfpu=fpv4-sp-d16
endif
#
# Architecture or project specific options
##############################################################################
##############################################################################
# Project, target, sources and paths
#
# Define project name here
PROJECT = ch
# Target settings.
MCU = cortex-m0
# Imported source files and paths.
BASE_PATH := ../../../../../../..
CHIBIOS := $(BASE_PATH)/ChibiOS/ChibiOS
CHIBIOS_CONTRIB := $(BASE_PATH)/ChibiOS/ChibiOS-Contrib
CONFDIR := ./cfg
BUILDDIR := ./build
DEPDIR := ./.dep
# Licensing files.
include $(CHIBIOS)/os/license/license.mk
# Startup files.
include $(CHIBIOS_CONTRIB)/os/common/startup/ARMCMx/compilers/GCC/mk/startup_NUC123SD4AN0.mk
# HAL-OSAL files (optional).
include $(CHIBIOS)/os/hal/hal.mk
include $(CHIBIOS_CONTRIB)/os/hal/ports/NUMICRO/NUC123SD4AN0/platform.mk
include $(CHIBIOS_CONTRIB)/os/hal/boards/NUTINY-SDK-NUC123-V2.0/board.mk
include $(CHIBIOS)/os/hal/osal/os-less/ARMCMx/osal.mk
# RTOS files (optional).
#include $(CHIBIOS)/os/rt/rt.mk
#include $(CHIBIOS)/os/common/ports/ARMv7-M/compilers/GCC/mk/port.mk
# Auto-build files in ./source recursively.
include $(CHIBIOS)/tools/mk/autobuild.mk
# Other files (optional).
#include $(CHIBIOS)/test/lib/test.mk
#include $(CHIBIOS)/test/rt/rt_test.mk
#include $(CHIBIOS)/test/oslib/oslib_test.mk
# Define linker script file here
LDSCRIPT= $(STARTUPLD_CONTRIB)/NUC123SD4AN0.ld
# C sources that can be compiled in ARM or THUMB mode depending on the global
# setting.
CSRC = $(ALLCSRC) \
$(TESTSRC) \
main.c
# C++ sources that can be compiled in ARM or THUMB mode depending on the global
# setting.
CPPSRC = $(ALLCPPSRC)
# List ASM source files here.
ASMSRC = $(ALLASMSRC)
# List ASM with preprocessor source files here.
ASMXSRC = $(ALLXASMSRC)
# Inclusion directories.
INCDIR = $(CONFDIR) $(ALLINC) $(TESTINC)
# Define C warning options here.
CWARN = -Wall -Wextra -Wundef -Wstrict-prototypes
# Define C++ warning options here.
CPPWARN = -Wall -Wextra -Wundef
#
# Project, target, sources and paths
##############################################################################
##############################################################################
# Start of user section
#
# List all user C define here, like -D_DEBUG=1
UDEFS =
# Define ASM defines here
UADEFS =
# List all user directories here
UINCDIR =
# List the user directory to look for the libraries here
ULIBDIR =
# List all user libraries here
ULIBS =
#
# End of user section
##############################################################################
##############################################################################
# Common rules
#
RULESPATH = $(CHIBIOS)/os/common/startup/ARMCMx/compilers/GCC/mk
include $(RULESPATH)/arm-none-eabi.mk
include $(RULESPATH)/rules.mk
#
# Common rules
##############################################################################
##############################################################################
# Custom rules
#
OPENOCD:=$(shell readlink -f `which openocd`)
OPENOCDPATH:=$(shell dirname $(OPENOCD))/../share/openocd
install-openocd-config:
rm $(OPENOCDPATH)/scripts/target/numicroM0.cfg && cp $(CHIBIOS_CONTRIB)/ext/numicroM0.cfg $(OPENOCDPATH)/scripts/target/
connect:
openocd -f ../scripts/interface/nulink.cfg -f ../scripts/target/numicroM0.cfg
flash: $(BUILDDIR)/$(PROJECT).elf
openocd -f ../scripts/interface/nulink.cfg -f ../scripts/target/numicroM0.cfg -c "program $< verify reset exit"
#
# Custom rules
##############################################################################

View File

@ -0,0 +1,531 @@
/*
ChibiOS - Copyright (C) 2020 Alex Lewontin
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.
*/
/**
* @file templates/halconf.h
* @brief HAL configuration header.
* @details HAL configuration file, this file allows to enable or disable the
* various device drivers from your application. You may also use
* this file in order to override the device drivers default settings.
*
* @addtogroup HAL_CONF
* @{
*/
#ifndef HALCONF_H
#define HALCONF_H
#define _CHIBIOS_HAL_CONF_
#define _CHIBIOS_HAL_CONF_VER_7_1_
#include "mcuconf.h"
/**
* @brief Enables the PAL subsystem.
*/
#if !defined(HAL_USE_PAL) || defined(__DOXYGEN__)
#define HAL_USE_PAL FALSE
#endif
/**
* @brief Enables the ADC subsystem.
*/
#if !defined(HAL_USE_ADC) || defined(__DOXYGEN__)
#define HAL_USE_ADC FALSE
#endif
/**
* @brief Enables the CAN subsystem.
*/
#if !defined(HAL_USE_CAN) || defined(__DOXYGEN__)
#define HAL_USE_CAN FALSE
#endif
/**
* @brief Enables the cryptographic subsystem.
*/
#if !defined(HAL_USE_CRY) || defined(__DOXYGEN__)
#define HAL_USE_CRY FALSE
#endif
/**
* @brief Enables the DAC subsystem.
*/
#if !defined(HAL_USE_DAC) || defined(__DOXYGEN__)
#define HAL_USE_DAC FALSE
#endif
/**
* @brief Enables the EFlash subsystem.
*/
#if !defined(HAL_USE_EFL) || defined(__DOXYGEN__)
#define HAL_USE_EFL FALSE
#endif
/**
* @brief Enables the GPT subsystem.
*/
#if !defined(HAL_USE_GPT) || defined(__DOXYGEN__)
#define HAL_USE_GPT FALSE
#endif
/**
* @brief Enables the I2C subsystem.
*/
#if !defined(HAL_USE_I2C) || defined(__DOXYGEN__)
#define HAL_USE_I2C FALSE
#endif
/**
* @brief Enables the I2S subsystem.
*/
#if !defined(HAL_USE_I2S) || defined(__DOXYGEN__)
#define HAL_USE_I2S FALSE
#endif
/**
* @brief Enables the ICU subsystem.
*/
#if !defined(HAL_USE_ICU) || defined(__DOXYGEN__)
#define HAL_USE_ICU FALSE
#endif
/**
* @brief Enables the MAC subsystem.
*/
#if !defined(HAL_USE_MAC) || defined(__DOXYGEN__)
#define HAL_USE_MAC FALSE
#endif
/**
* @brief Enables the MMC_SPI subsystem.
*/
#if !defined(HAL_USE_MMC_SPI) || defined(__DOXYGEN__)
#define HAL_USE_MMC_SPI FALSE
#endif
/**
* @brief Enables the PWM subsystem.
*/
#if !defined(HAL_USE_PWM) || defined(__DOXYGEN__)
#define HAL_USE_PWM TRUE
#endif
/**
* @brief Enables the RTC subsystem.
*/
#if !defined(HAL_USE_RTC) || defined(__DOXYGEN__)
#define HAL_USE_RTC FALSE
#endif
/**
* @brief Enables the SDC subsystem.
*/
#if !defined(HAL_USE_SDC) || defined(__DOXYGEN__)
#define HAL_USE_SDC FALSE
#endif
/**
* @brief Enables the SERIAL subsystem.
*/
#if !defined(HAL_USE_SERIAL) || defined(__DOXYGEN__)
#define HAL_USE_SERIAL FALSE
#endif
/**
* @brief Enables the SERIAL over USB subsystem.
*/
#if !defined(HAL_USE_SERIAL_USB) || defined(__DOXYGEN__)
#define HAL_USE_SERIAL_USB FALSE
#endif
/**
* @brief Enables the SIO subsystem.
*/
#if !defined(HAL_USE_SIO) || defined(__DOXYGEN__)
#define HAL_USE_SIO FALSE
#endif
/**
* @brief Enables the SPI subsystem.
*/
#if !defined(HAL_USE_SPI) || defined(__DOXYGEN__)
#define HAL_USE_SPI FALSE
#endif
/**
* @brief Enables the TRNG subsystem.
*/
#if !defined(HAL_USE_TRNG) || defined(__DOXYGEN__)
#define HAL_USE_TRNG FALSE
#endif
/**
* @brief Enables the UART subsystem.
*/
#if !defined(HAL_USE_UART) || defined(__DOXYGEN__)
#define HAL_USE_UART FALSE
#endif
/**
* @brief Enables the USB subsystem.
*/
#if !defined(HAL_USE_USB) || defined(__DOXYGEN__)
#define HAL_USE_USB FALSE
#endif
/**
* @brief Enables the WDG subsystem.
*/
#if !defined(HAL_USE_WDG) || defined(__DOXYGEN__)
#define HAL_USE_WDG FALSE
#endif
/**
* @brief Enables the WSPI subsystem.
*/
#if !defined(HAL_USE_WSPI) || defined(__DOXYGEN__)
#define HAL_USE_WSPI FALSE
#endif
/*===========================================================================*/
/* PAL driver related settings. */
/*===========================================================================*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(PAL_USE_CALLBACKS) || defined(__DOXYGEN__)
#define PAL_USE_CALLBACKS FALSE
#endif
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(PAL_USE_WAIT) || defined(__DOXYGEN__)
#define PAL_USE_WAIT FALSE
#endif
/*===========================================================================*/
/* ADC driver related settings. */
/*===========================================================================*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(ADC_USE_WAIT) || defined(__DOXYGEN__)
#define ADC_USE_WAIT TRUE
#endif
/**
* @brief Enables the @p adcAcquireBus() and @p adcReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(ADC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define ADC_USE_MUTUAL_EXCLUSION TRUE
#endif
/*===========================================================================*/
/* CAN driver related settings. */
/*===========================================================================*/
/**
* @brief Sleep mode related APIs inclusion switch.
*/
#if !defined(CAN_USE_SLEEP_MODE) || defined(__DOXYGEN__)
#define CAN_USE_SLEEP_MODE TRUE
#endif
/**
* @brief Enforces the driver to use direct callbacks rather than OSAL events.
*/
#if !defined(CAN_ENFORCE_USE_CALLBACKS) || defined(__DOXYGEN__)
#define CAN_ENFORCE_USE_CALLBACKS FALSE
#endif
/*===========================================================================*/
/* CRY driver related settings. */
/*===========================================================================*/
/**
* @brief Enables the SW fall-back of the cryptographic driver.
* @details When enabled, this option, activates a fall-back software
* implementation for algorithms not supported by the underlying
* hardware.
* @note Fall-back implementations may not be present for all algorithms.
*/
#if !defined(HAL_CRY_USE_FALLBACK) || defined(__DOXYGEN__)
#define HAL_CRY_USE_FALLBACK FALSE
#endif
/**
* @brief Makes the driver forcibly use the fall-back implementations.
*/
#if !defined(HAL_CRY_ENFORCE_FALLBACK) || defined(__DOXYGEN__)
#define HAL_CRY_ENFORCE_FALLBACK FALSE
#endif
/*===========================================================================*/
/* DAC driver related settings. */
/*===========================================================================*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(DAC_USE_WAIT) || defined(__DOXYGEN__)
#define DAC_USE_WAIT TRUE
#endif
/**
* @brief Enables the @p dacAcquireBus() and @p dacReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(DAC_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define DAC_USE_MUTUAL_EXCLUSION TRUE
#endif
/*===========================================================================*/
/* I2C driver related settings. */
/*===========================================================================*/
/**
* @brief Enables the mutual exclusion APIs on the I2C bus.
*/
#if !defined(I2C_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define I2C_USE_MUTUAL_EXCLUSION TRUE
#endif
/*===========================================================================*/
/* MAC driver related settings. */
/*===========================================================================*/
/**
* @brief Enables the zero-copy API.
*/
#if !defined(MAC_USE_ZERO_COPY) || defined(__DOXYGEN__)
#define MAC_USE_ZERO_COPY FALSE
#endif
/**
* @brief Enables an event sources for incoming packets.
*/
#if !defined(MAC_USE_EVENTS) || defined(__DOXYGEN__)
#define MAC_USE_EVENTS TRUE
#endif
/*===========================================================================*/
/* MMC_SPI driver related settings. */
/*===========================================================================*/
/**
* @brief Delays insertions.
* @details If enabled this options inserts delays into the MMC waiting
* routines releasing some extra CPU time for the threads with
* lower priority, this may slow down the driver a bit however.
* This option is recommended also if the SPI driver does not
* use a DMA channel and heavily loads the CPU.
*/
#if !defined(MMC_NICE_WAITING) || defined(__DOXYGEN__)
#define MMC_NICE_WAITING TRUE
#endif
/*===========================================================================*/
/* SDC driver related settings. */
/*===========================================================================*/
/**
* @brief Number of initialization attempts before rejecting the card.
* @note Attempts are performed at 10mS intervals.
*/
#if !defined(SDC_INIT_RETRY) || defined(__DOXYGEN__)
#define SDC_INIT_RETRY 100
#endif
/**
* @brief Include support for MMC cards.
* @note MMC support is not yet implemented so this option must be kept
* at @p FALSE.
*/
#if !defined(SDC_MMC_SUPPORT) || defined(__DOXYGEN__)
#define SDC_MMC_SUPPORT FALSE
#endif
/**
* @brief Delays insertions.
* @details If enabled this options inserts delays into the MMC waiting
* routines releasing some extra CPU time for the threads with
* lower priority, this may slow down the driver a bit however.
*/
#if !defined(SDC_NICE_WAITING) || defined(__DOXYGEN__)
#define SDC_NICE_WAITING TRUE
#endif
/**
* @brief OCR initialization constant for V20 cards.
*/
#if !defined(SDC_INIT_OCR_V20) || defined(__DOXYGEN__)
#define SDC_INIT_OCR_V20 0x50FF8000U
#endif
/**
* @brief OCR initialization constant for non-V20 cards.
*/
#if !defined(SDC_INIT_OCR) || defined(__DOXYGEN__)
#define SDC_INIT_OCR 0x80100000U
#endif
/*===========================================================================*/
/* SERIAL driver related settings. */
/*===========================================================================*/
/**
* @brief Default bit rate.
* @details Configuration parameter, this is the baud rate selected for the
* default configuration.
*/
#if !defined(SERIAL_DEFAULT_BITRATE) || defined(__DOXYGEN__)
#define SERIAL_DEFAULT_BITRATE 38400
#endif
/**
* @brief Serial buffers size.
* @details Configuration parameter, you can change the depth of the queue
* buffers depending on the requirements of your application.
* @note The default is 16 bytes for both the transmission and receive
* buffers.
*/
#if !defined(SERIAL_BUFFERS_SIZE) || defined(__DOXYGEN__)
#define SERIAL_BUFFERS_SIZE 32
#endif
/*===========================================================================*/
/* SERIAL_USB driver related setting. */
/*===========================================================================*/
/**
* @brief Serial over USB buffers size.
* @details Configuration parameter, the buffer size must be a multiple of
* the USB data endpoint maximum packet size.
* @note The default is 256 bytes for both the transmission and receive
* buffers.
*/
#if !defined(SERIAL_USB_BUFFERS_SIZE) || defined(__DOXYGEN__)
#define SERIAL_USB_BUFFERS_SIZE 256
#endif
/**
* @brief Serial over USB number of buffers.
* @note The default is 2 buffers.
*/
#if !defined(SERIAL_USB_BUFFERS_NUMBER) || defined(__DOXYGEN__)
#define SERIAL_USB_BUFFERS_NUMBER 2
#endif
/*===========================================================================*/
/* SPI driver related settings. */
/*===========================================================================*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_WAIT) || defined(__DOXYGEN__)
#define SPI_USE_WAIT TRUE
#endif
/**
* @brief Enables circular transfers APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_CIRCULAR) || defined(__DOXYGEN__)
#define SPI_USE_CIRCULAR FALSE
#endif
/**
* @brief Enables the @p spiAcquireBus() and @p spiReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define SPI_USE_MUTUAL_EXCLUSION TRUE
#endif
/**
* @brief Handling method for SPI CS line.
* @note Disabling this option saves both code and data space.
*/
#if !defined(SPI_SELECT_MODE) || defined(__DOXYGEN__)
#define SPI_SELECT_MODE SPI_SELECT_MODE_PAD
#endif
/*===========================================================================*/
/* UART driver related settings. */
/*===========================================================================*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(UART_USE_WAIT) || defined(__DOXYGEN__)
#define UART_USE_WAIT FALSE
#endif
/**
* @brief Enables the @p uartAcquireBus() and @p uartReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(UART_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define UART_USE_MUTUAL_EXCLUSION FALSE
#endif
/*===========================================================================*/
/* USB driver related settings. */
/*===========================================================================*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(USB_USE_WAIT) || defined(__DOXYGEN__)
#define USB_USE_WAIT FALSE
#endif
/*===========================================================================*/
/* WSPI driver related settings. */
/*===========================================================================*/
/**
* @brief Enables synchronous APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(WSPI_USE_WAIT) || defined(__DOXYGEN__)
#define WSPI_USE_WAIT TRUE
#endif
/**
* @brief Enables the @p wspiAcquireBus() and @p wspiReleaseBus() APIs.
* @note Disabling this option saves both code and data space.
*/
#if !defined(WSPI_USE_MUTUAL_EXCLUSION) || defined(__DOXYGEN__)
#define WSPI_USE_MUTUAL_EXCLUSION TRUE
#endif
#endif /* HALCONF_H */
/** @} */

View File

@ -0,0 +1,34 @@
/*
Copyright (C) 2016 Stephane D'Alu
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.
*/
#ifndef _MCUCONF_H_
#define _MCUCONF_H_
/*
* Board setting
*/
/*
* HAL driver system settings.
*/
#define NUC123_HSE_ENABLED TRUE
#define NUC123_PLL_ENABLED TRUE
#define NUC123_PLLSRC NUC123_PLLSRC_HSE
#define NUC123_HCLKSRC NUC123_HCLKSRC_PLL
#define NUC123SD4AN0_MCUCONF
#endif /* _MCUCONF_H_ */

View File

@ -0,0 +1,67 @@
/*
ChibiOS - Copyright (C) 2006..2018 Giovanni Di Sirio
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.
*/
/**
* @file templates/halconf.h
* @brief Bare-metal OSAL configuration header.
*
* @addtogroup OSAL_CONF
* @{
*/
#ifndef OSALCONF_H
#define OSALCONF_H
/**
* @brief Frequency in Hertz of the system tick.
*/
#if !defined(OSAL_ST_FREQUENCY) || defined(__DOXYGEN__)
#define OSAL_ST_FREQUENCY 10000
#endif
/**
* @brief Enables OSAL assertions.
*/
#if !defined(OSAL_DBG_ENABLE_ASSERTS) || defined(__DOXYGEN__)
#define OSAL_DBG_ENABLE_ASSERTS FALSE
#endif
/**
* @brief Enables OSAL functions parameters checks.
*/
#if !defined(OSAL_DBG_ENABLE_CHECKS) || defined(__DOXYGEN__)
#define OSAL_DBG_ENABLE_CHECKS FALSE
#endif
/**
* @brief OSAL initialization hook.
*/
#if !defined(OSAL_INIT_HOOK) || defined(__DOXYGEN__)
#define OSAL_INIT_HOOK() { \
}
#endif
/**
* @brief Idle loop hook macro.
*/
#if !defined(OSAL_IDLE_HOOK) || defined(__DOXYGEN__)
#define OSAL_IDLE_HOOK() { \
}
#endif
#endif /* OSALCONF_H */
/** @} */

View File

@ -0,0 +1,97 @@
/*
Adapted from ChibiOS-Contrib/testhal/KINETIS/FRDM-KL25Z/PWM
(c) 2015 flabbergast <s3+flabbergast@sdfeu.org>
Modifications copyright (C) 2020 Alex Lewontin
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 "hal.h"
const PWMConfig pwmcfg = {
750000,
1000,
NULL,
{
{PWM_OUTPUT_ACTIVE_HIGH, NULL, NUC123_PWM_CH0_PIN_PA12},
{PWM_OUTPUT_ACTIVE_LOW, NULL, NUC123_PWM_CH1_PIN_PA13},
{PWM_OUTPUT_DISABLED, NULL, NUC123_PWM_CH2_PIN_NONE},
{PWM_OUTPUT_DISABLED, NULL, NUC123_PWM_CH3_PIN_NONE},
},
};
#define BREATHE_STEP 16 /* ms; = 4000ms/TABLE_SIZE */
/* Breathing Sleep LED brighness(PWM On period) table
*
* http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
* (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
*/
/* ruby -e "a = ((0..255).map{|x| Math.exp(Math.cos(Math::PI+(2*x*(Math::PI)/255)))-Math.exp(-1) }); m = a.max; a.map\!{|x| (10000*x/m).to_i}; p a" */
#define TABLE_SIZE 256
static const uint16_t breathing_table[TABLE_SIZE] = {
0, 0, 1, 4, 7, 11, 17, 23, 30, 38, 47, 58,
69, 81, 94, 109, 124, 141, 159, 177, 197, 218, 241, 264,
289, 315, 343, 372, 402, 433, 466, 501, 537, 574, 613, 654,
696, 741, 786, 834, 883, 935, 988, 1043, 1100, 1159, 1220, 1283,
1349, 1416, 1486, 1558, 1632, 1709, 1788, 1870, 1954, 2040, 2129, 2220,
2314, 2411, 2510, 2611, 2715, 2822, 2932, 3044, 3158, 3275, 3395, 3517,
3641, 3768, 3897, 4028, 4162, 4298, 4436, 4576, 4717, 4861, 5006, 5152,
5300, 5449, 5600, 5751, 5903, 6055, 6208, 6361, 6513, 6666, 6818, 6970,
7120, 7269, 7417, 7563, 7708, 7850, 7990, 8127, 8261, 8391, 8519, 8643,
8762, 8878, 8989, 9095, 9196, 9293, 9383, 9469, 9548, 9622, 9689, 9750,
9805, 9853, 9895, 9930, 9957, 9978, 9992, 9999, 10000, 9992, 9978, 9957,
9930, 9895, 9853, 9805, 9750, 9689, 9622, 9548, 9469, 9383, 9293, 9196,
9095, 8989, 8878, 8762, 8643, 8519, 8391, 8261, 8127, 7990, 7850, 7708,
7563, 7417, 7269, 7120, 6970, 6818, 6666, 6513, 6361, 6208, 6055, 5903,
5751, 5600, 5449, 5300, 5152, 5006, 4861, 4717, 4576, 4436, 4298, 4162,
4028, 3897, 3768, 3641, 3517, 3395, 3275, 3158, 3044, 2932, 2822, 2715,
2611, 2510, 2411, 2314, 2220, 2129, 2040, 1954, 1870, 1788, 1709, 1632,
1558, 1486, 1416, 1349, 1283, 1220, 1159, 1100, 1043, 988, 935, 883,
834, 786, 741, 696, 654, 613, 574, 537, 501, 466, 433, 402,
372, 343, 315, 289, 264, 241, 218, 197, 177, 159, 141, 124,
109, 94, 81, 69, 58, 47, 38, 30, 23, 17, 11, 7,
4, 1, 0, 0};
uint16_t table_pos = 0;
/*
* Application entry point.
*/
int main(void)
{
/*
* System initializations.
* - HAL initialization, this also initializes the configured device drivers
* and performs the board-specific initializations.
*/
halInit();
/*
* Enabling interrupts, initialization done.
*/
osalSysEnable();
pwmStart(&PWMD1, &pwmcfg);
pwmEnableChannel(&PWMD1, 0, 0);
pwmEnableChannel(&PWMD1, 1, 0);
while (true) {
osalThreadSleepMilliseconds(BREATHE_STEP);
pwmEnableChannel(&PWMD1, 0, PWM_PERCENTAGE_TO_WIDTH(&PWMD1, breathing_table[table_pos]));
pwmEnableChannel(&PWMD1, 1, PWM_PERCENTAGE_TO_WIDTH(&PWMD1, breathing_table[table_pos]));
table_pos = (table_pos + 1) % TABLE_SIZE;
}
}

View File

@ -0,0 +1,26 @@
*****************************************************************************
** ChibiOS/HAL - PWM driver demo for NUC123. **
*****************************************************************************
** TARGET **
The demo runs on a NUTINY-SDK-NUC123-V2.0 board with a NUC123SD4AN0 MCU.
** The Demo **
The application demonstrates the use of the NUC123 PWM driver. When successful,
pins 44 and 45 should carry a 750 Hz square wave, the duty cycle of which
sinusoidally oscillates between 0% and 100%. One channel is active high, and
the other is active low.
** Board Setup **
There are multiple ways to observe the PWM output:
- Attach channels of a logic analyzer to pins 44 & 45, and a ground pin. Set it
to trigger on either (but not both) the rising or falling edge of either (but
not both) channel.
** Build Procedure **
The demo has been tested using gcc version 9.3.1 (GNU Arm Embedded Toolchain 9-2020-q2-update).
Just modify the TRGT line in the makefile in order to use different GCC ports.