-
Notifications
You must be signed in to change notification settings - Fork 919
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Change div_int_frac methods to be suffixed by the number of bits of fraction e.g. div_int_frac8 #1926
base: develop
Are you sure you want to change the base?
Change div_int_frac methods to be suffixed by the number of bits of fraction e.g. div_int_frac8 #1926
Changes from all commits
138f96a
b5e41b3
40503a9
cbca882
8eed92e
1c4e72e
8a72865
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -354,9 +354,26 @@ void clocks_enable_resus(resus_callback_t resus_callback); | |
* \param gpio The GPIO pin to output the clock to. Valid GPIOs are: 21, 23, 24, 25. These GPIOs are connected to the GPOUT0-3 clock generators. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that there's a #if !PICO_RP2040
else if (gpio == 13) gpclk = clk_gpout0;
else if (gpio == 15) gpclk = clk_gpout1;
#endif in the code, so do we need one of those |
||
* \param src The source clock. See the register field CLOCKS_CLK_GPOUT0_CTRL_AUXSRC for a full list. The list is the same for each GPOUT clock generator. | ||
* \param div_int The integer part of the value to divide the source clock by. This is useful to not overwhelm the GPIO pin with a fast clock. this is in range of 1..2^24-1. | ||
lurch marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* \param div_frac The fractional part of the value to divide the source clock by. This is in range of 0..255 (/256). | ||
* \param div_frac16 The fractional part of the value to divide the source clock by. This is in range of 0..65536 (/65536). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Presumably the range is |
||
*/ | ||
void clock_gpio_init_int_frac(uint gpio, uint src, uint32_t div_int, uint8_t div_frac); | ||
void clock_gpio_init_int_frac16(uint gpio, uint src, uint32_t div_int, uint16_t div_frac16); | ||
lurch marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
/*! \brief Output an optionally divided clock to the specified gpio pin. | ||
* \ingroup hardware_clocks | ||
* | ||
* \param gpio The GPIO pin to output the clock to. Valid GPIOs are: 21, 23, 24, 25. These GPIOs are connected to the GPOUT0-3 clock generators. | ||
* \param src The source clock. See the register field CLOCKS_CLK_GPOUT0_CTRL_AUXSRC for a full list. The list is the same for each GPOUT clock generator. | ||
* \param div_int The integer part of the value to divide the source clock by. This is useful to not overwhelm the GPIO pin with a fast clock. this is in range of 1..2^24-1. | ||
* \param div_frac8 The fractional part of the value to divide the source clock by. This is in range of 0..255 (/256). | ||
*/ | ||
static inline void clock_gpio_init_int_frac8(uint gpio, uint src, uint32_t div_int, uint8_t div_frac8) { | ||
return clock_gpio_init_int_frac16(gpio, src, div_int, (uint16_t)(div_frac8 << 8u)); | ||
} | ||
|
||
// backwards compatibility | ||
static inline void clock_gpio_init_int_frac(uint gpio, uint src, uint32_t div_int, uint8_t div_frac8) { | ||
return clock_gpio_init_int_frac8(gpio, src, div_int, div_frac8); | ||
} | ||
|
||
/*! \brief Output an optionally divided clock to the specified gpio pin. | ||
* \ingroup hardware_clocks | ||
|
@@ -368,8 +385,15 @@ void clock_gpio_init_int_frac(uint gpio, uint src, uint32_t div_int, uint8_t div | |
static inline void clock_gpio_init(uint gpio, uint src, float div) | ||
{ | ||
uint div_int = (uint)div; | ||
uint8_t frac = (uint8_t)((div - (float)div_int) * (1u << CLOCKS_CLK_GPOUT0_DIV_INT_LSB)); | ||
clock_gpio_init_int_frac(gpio, src, div_int, frac); | ||
#if CLOCKS_CLK_GPOUT0_DIV_FRAC_MSB - CLOCKS_CLK_GPOUT0_DIV_FRAC_LSB == 15 | ||
uint16_t frac = (uint16_t)((div - (float)div_int) * (1u << 16)); | ||
clock_gpio_init_int_frac16(gpio, src, div_int, frac); | ||
#elif CLOCKS_CLK_GPOUT0_DIV_FRAC_MSB - CLOCKS_CLK_GPOUT0_DIV_FRAC_LSB == 7 | ||
uint8_t frac = (uint8_t)((div - (float)div_int) * (1u << 8)); | ||
clock_gpio_init_int_frac8(gpio, src, div_int, frac); | ||
#else | ||
#error unsupported number of fractional bits | ||
#endif | ||
} | ||
|
||
/*! \brief Configure a clock to come from a gpio input | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -468,26 +468,44 @@ static inline void sm_config_set_sideset(pio_sm_config *c, uint bit_count, bool | |
* | ||
* \param c Pointer to the configuration structure to modify | ||
* \param div_int Integer part of the divisor | ||
* \param div_frac Fractional part in 1/256ths | ||
* \param div_frac8 Fractional part in 1/256ths | ||
* \sa sm_config_set_clkdiv() | ||
*/ | ||
static inline void sm_config_set_clkdiv_int_frac(pio_sm_config *c, uint16_t div_int, uint8_t div_frac) { | ||
invalid_params_if(HARDWARE_PIO, div_int == 0 && div_frac != 0); | ||
static inline void sm_config_set_clkdiv_int_frac8(pio_sm_config *c, uint32_t div_int, uint8_t div_frac8) { | ||
static_assert(PIO_SM0_CLKDIV_INT_MSB - PIO_SM0_CLKDIV_INT_LSB == 15, ""); | ||
invalid_params_if(HARDWARE_PIO, div_int >> 16); | ||
invalid_params_if(HARDWARE_PIO, div_int == 0 && div_frac8 != 0); | ||
static_assert(PIO_SM0_CLKDIV_FRAC_MSB - PIO_SM0_CLKDIV_FRAC_LSB == 7, ""); | ||
c->clkdiv = | ||
(((uint)div_frac) << PIO_SM0_CLKDIV_FRAC_LSB) | | ||
(((uint)div_frac8) << PIO_SM0_CLKDIV_FRAC_LSB) | | ||
(((uint)div_int) << PIO_SM0_CLKDIV_INT_LSB); | ||
} | ||
|
||
static inline void pio_calculate_clkdiv_from_float(float div, uint16_t *div_int, uint8_t *div_frac) { | ||
// backwards compatibility | ||
static inline void sm_config_set_clkdiv_int_frac(pio_sm_config *c, uint16_t div_int, uint8_t div_frac8) { | ||
sm_config_set_clkdiv_int_frac8(c, div_int, div_frac8); | ||
} | ||
|
||
static inline void pio_calculate_clkdiv8_from_float(float div, uint32_t *div_int, uint8_t *div_frac8) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For the function named There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The 8 does seem confusing. It's presumably referring to the frac8? This isn't presumably supposed to be part of the API even though it's in the header. So maybe it doesn't matter |
||
valid_params_if(HARDWARE_PIO, div >= 1 && div <= 65536); | ||
*div_int = (uint16_t)div; | ||
// not a strictly necessary check, but if this changes, then this method should | ||
// probably no longer be used in favor of one with a larger fraction | ||
static_assert(PIO_SM0_CLKDIV_FRAC_MSB - PIO_SM0_CLKDIV_FRAC_LSB == 7, ""); | ||
if (*div_int == 0) { | ||
*div_frac = 0; | ||
*div_frac8 = 0; | ||
} else { | ||
*div_frac = (uint8_t)((div - (float)*div_int) * (1u << 8u)); | ||
*div_frac8 = (uint8_t)((div - (float)*div_int) * (1u << 8u)); | ||
} | ||
} | ||
|
||
// backwards compatibility | ||
static inline void pio_calculate_clkdiv_from_float(float div, uint16_t *div_int16, uint8_t *div_frac8) { | ||
uint32_t div_int; | ||
pio_calculate_clkdiv8_from_float(div, &div_int, div_frac8); | ||
*div_int16 = (uint16_t) div_int; | ||
} | ||
|
||
/*! \brief Set the state machine clock divider (from a floating point value) in a state machine configuration | ||
* \ingroup sm_config | ||
* | ||
|
@@ -504,10 +522,10 @@ static inline void pio_calculate_clkdiv_from_float(float div, uint16_t *div_int, | |
* although it will depend on the use case. | ||
*/ | ||
static inline void sm_config_set_clkdiv(pio_sm_config *c, float div) { | ||
uint16_t div_int; | ||
uint8_t div_frac; | ||
pio_calculate_clkdiv_from_float(div, &div_int, &div_frac); | ||
sm_config_set_clkdiv_int_frac(c, div_int, div_frac); | ||
uint32_t div_int; | ||
uint8_t div_frac8; | ||
pio_calculate_clkdiv8_from_float(div, &div_int, &div_frac8); | ||
sm_config_set_clkdiv_int_frac8(c, div_int, div_frac8); | ||
} | ||
|
||
/*! \brief Set the wrap addresses in a state machine configuration | ||
|
@@ -664,7 +682,7 @@ static inline pio_sm_config pio_get_default_sm_config(void) { | |
#if PICO_PIO_USE_GPIO_BASE | ||
c.pinhi = -1; | ||
#endif | ||
sm_config_set_clkdiv_int_frac(&c, 1, 0); | ||
sm_config_set_clkdiv_int_frac8(&c, 1, 0); | ||
sm_config_set_wrap(&c, 0, 31); | ||
sm_config_set_in_shift(&c, true, false, 32); | ||
sm_config_set_out_shift(&c, true, false, 32); | ||
|
@@ -1643,17 +1661,25 @@ void pio_sm_drain_tx_fifo(PIO pio, uint sm); | |
* \param pio The PIO instance; e.g. \ref pio0 or \ref pio1 | ||
* \param sm State machine index (0..3) | ||
* \param div_int the integer part of the clock divider | ||
* \param div_frac the fractional part of the clock divider in 1/256s | ||
* \param div_frac8 the fractional part of the clock divider in 1/256s | ||
*/ | ||
static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int, uint8_t div_frac) { | ||
static inline void pio_sm_set_clkdiv_int_frac8(PIO pio, uint sm, uint32_t div_int, uint8_t div_frac8) { | ||
check_pio_param(pio); | ||
check_sm_param(sm); | ||
invalid_params_if(HARDWARE_PIO, div_int == 0 && div_frac != 0); | ||
static_assert(PIO_SM0_CLKDIV_INT_MSB - PIO_SM0_CLKDIV_INT_LSB == 15, ""); | ||
invalid_params_if(HARDWARE_PIO, div_int >> 16); | ||
invalid_params_if(HARDWARE_PIO, div_int == 0 && div_frac8 != 0); | ||
static_assert(PIO_SM0_CLKDIV_FRAC_MSB - PIO_SM0_CLKDIV_FRAC_LSB == 7, ""); | ||
pio->sm[sm].clkdiv = | ||
(((uint)div_frac) << PIO_SM0_CLKDIV_FRAC_LSB) | | ||
(((uint)div_frac8) << PIO_SM0_CLKDIV_FRAC_LSB) | | ||
(((uint)div_int) << PIO_SM0_CLKDIV_INT_LSB); | ||
} | ||
|
||
// backwards compatibility | ||
static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int, uint8_t div_frac8) { | ||
pio_sm_set_clkdiv_int_frac8(pio, sm, div_int, div_frac8); | ||
} | ||
|
||
/*! \brief set the current clock divider for a state machine | ||
* \ingroup hardware_pio | ||
* | ||
|
@@ -1664,10 +1690,10 @@ static inline void pio_sm_set_clkdiv_int_frac(PIO pio, uint sm, uint16_t div_int | |
static inline void pio_sm_set_clkdiv(PIO pio, uint sm, float div) { | ||
check_pio_param(pio); | ||
check_sm_param(sm); | ||
uint16_t div_int; | ||
uint32_t div_int; | ||
uint8_t div_frac; | ||
pio_calculate_clkdiv_from_float(div, &div_int, &div_frac); | ||
pio_sm_set_clkdiv_int_frac(pio, sm, div_int, div_frac); | ||
pio_calculate_clkdiv8_from_float(div, &div_int, &div_frac); | ||
pio_sm_set_clkdiv_int_frac8(pio, sm, div_int, div_frac); | ||
} | ||
|
||
/*! \brief Clear a state machine's TX and RX FIFOs | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -162,32 +162,38 @@ static inline void pwm_config_set_clkdiv(pwm_config *c, float div) { | |
* \ingroup hardware_pwm | ||
* | ||
* \param c PWM configuration struct to modify | ||
* \param integer 8 bit integer part of the clock divider. Must be greater than or equal to 1. | ||
* \param fract 4 bit fractional part of the clock divider | ||
* \param div_int 8 bit integer part of the clock divider. Must be greater than or equal to 1. | ||
* \param div_frac4 4 bit fractional part of the clock divider | ||
* | ||
* If the divide mode is free-running, the PWM counter runs at clk_sys / div. | ||
* Otherwise, the divider reduces the rate of events seen on the B pin input (level or edge) | ||
* before passing them on to the PWM counter. | ||
*/ | ||
static inline void pwm_config_set_clkdiv_int_frac(pwm_config *c, uint8_t integer, uint8_t fract) { | ||
valid_params_if(HARDWARE_PWM, integer >= 1); | ||
valid_params_if(HARDWARE_PWM, fract < 16); | ||
c->div = (((uint)integer) << PWM_CH0_DIV_INT_LSB) | (((uint)fract) << PWM_CH0_DIV_FRAC_LSB); | ||
static inline void pwm_config_set_clkdiv_int_frac4(pwm_config *c, uint32_t div_int, uint8_t div_frac4) { | ||
static_assert(PWM_CH0_DIV_INT_MSB - PWM_CH0_DIV_INT_LSB == 7, ""); | ||
valid_params_if(HARDWARE_PWM, div_int >= 1 && div_int < 256); | ||
static_assert(PWM_CH0_DIV_FRAC_MSB - PWM_CH0_DIV_FRAC_LSB == 3, ""); | ||
valid_params_if(HARDWARE_PWM, div_frac4 < 16); | ||
c->div = (((uint)div_int) << PWM_CH0_DIV_INT_LSB) | (((uint)div_frac4) << PWM_CH0_DIV_FRAC_LSB); | ||
} | ||
|
||
// backwards compatibility | ||
static inline void pwm_config_set_clkdiv_int_frac(pwm_config *c, uint8_t div_int, uint8_t div_frac4) { | ||
pwm_config_set_clkdiv_int_frac4(c, div_int, div_frac4); | ||
} | ||
|
||
/** \brief Set PWM clock divider in a PWM configuration | ||
* \ingroup hardware_pwm | ||
* | ||
* \param c PWM configuration struct to modify | ||
* \param div Integer value to reduce counting rate by. Must be greater than or equal to 1. | ||
* \param div_int Integer value to reduce counting rate by. Must be greater than or equal to 1 annd less than 256. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. annd -> and |
||
* | ||
* If the divide mode is free-running, the PWM counter runs at clk_sys / div. | ||
* Otherwise, the divider reduces the rate of events seen on the B pin input (level or edge) | ||
* before passing them on to the PWM counter. | ||
*/ | ||
static inline void pwm_config_set_clkdiv_int(pwm_config *c, uint div) { | ||
valid_params_if(HARDWARE_PWM, div >= 1 && div < 256); | ||
pwm_config_set_clkdiv_int_frac(c, (uint8_t)div, 0); | ||
static inline void pwm_config_set_clkdiv_int(pwm_config *c, uint32_t div_int) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems curious that PWM has an integer-divider-only function, but none of the other hardware APIs do? 🤔 |
||
pwm_config_set_clkdiv_int_frac4(c, div_int, 0); | ||
} | ||
|
||
/** \brief Set PWM counting mode in a PWM configuration | ||
|
@@ -427,14 +433,20 @@ static inline void pwm_retard_count(uint slice_num) { | |
* Set the clock divider. Counter increment will be on sysclock divided by this value, taking into account the gating. | ||
* | ||
* \param slice_num PWM slice number | ||
* \param integer 8 bit integer part of the clock divider | ||
* \param fract 4 bit fractional part of the clock divider | ||
* \param div_int 8 bit integer part of the clock divider | ||
* \param div_frac4 4 bit fractional part of the clock divider | ||
*/ | ||
static inline void pwm_set_clkdiv_int_frac(uint slice_num, uint8_t integer, uint8_t fract) { | ||
static inline void pwm_set_clkdiv_int_frac4(uint slice_num, uint8_t div_int, uint8_t div_frac4) { | ||
check_slice_num_param(slice_num); | ||
valid_params_if(HARDWARE_PWM, integer >= 1); | ||
valid_params_if(HARDWARE_PWM, fract < 16); | ||
pwm_hw->slice[slice_num].div = (((uint)integer) << PWM_CH0_DIV_INT_LSB) | (((uint)fract) << PWM_CH0_DIV_FRAC_LSB); | ||
valid_params_if(HARDWARE_PWM, div_int >= 1); | ||
static_assert(PWM_CH0_DIV_FRAC_MSB - PWM_CH0_DIV_FRAC_LSB == 3, ""); | ||
valid_params_if(HARDWARE_PWM, div_frac4 < 16); | ||
pwm_hw->slice[slice_num].div = (((uint)div_int) << PWM_CH0_DIV_INT_LSB) | (((uint)div_frac4) << PWM_CH0_DIV_FRAC_LSB); | ||
} | ||
|
||
// backwards compatibility | ||
static inline void pwm_set_clkdiv_int_frac(uint slice_num, uint8_t div_int, uint8_t div_frac4) { | ||
pwm_set_clkdiv_int_frac4(slice_num, div_int, div_frac4); | ||
} | ||
|
||
/** \brief Set PWM clock divider | ||
|
@@ -450,7 +462,7 @@ static inline void pwm_set_clkdiv(uint slice_num, float divider) { | |
valid_params_if(HARDWARE_PWM, divider >= 1.f && divider < 256.f); | ||
uint8_t i = (uint8_t)divider; | ||
uint8_t f = (uint8_t)((divider - i) * (0x01 << 4)); | ||
pwm_set_clkdiv_int_frac(slice_num, i, f); | ||
pwm_set_clkdiv_int_frac4(slice_num, i, f); | ||
} | ||
|
||
/** \brief Set PWM output polarity | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -54,13 +54,22 @@ void cyw43_driver_deinit(struct async_context *context); | |
#endif | ||
#endif | ||
|
||
// PICO_CONFIG: CYW43_PIO_CLOCK_DIV_FRAC, Fractional part of the clock divider for communication with the wireless chip, type=bool, default=0, group=pico_cyw43_driver | ||
#ifndef CYW43_PIO_CLOCK_DIV_FRAC | ||
#define CYW43_PIO_CLOCK_DIV_FRAC 0 | ||
// PICO_CONFIG: CYW43_PIO_CLOCK_DIV_FRAC8, Fractional part of the clock divider for communication with the wireless chip 0-255, type=bool, default=0, group=pico_cyw43_driver | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess you could add |
||
#ifndef CYW43_PIO_CLOCK_DIV_FRAC8 | ||
#ifdef CYW43_PIO_CLOCK_DIV_FRAC | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might not hurt to add a |
||
#define CYW43_PIO_CLOCK_DIV_FRAC8 CYW43_PIO_CLOCK_DIV_FRAC | ||
#else | ||
#define CYW43_PIO_CLOCK_DIV_FRAC8 0 | ||
#endif | ||
#endif | ||
|
||
#if CYW43_PIO_CLOCK_DIV_DYNAMIC | ||
void cyw43_set_pio_clock_divisor(uint16_t clock_div_int, uint8_t clock_div_frac); | ||
void cyw43_set_pio_clkdiv_int_frac8(uint32_t clock_div_int, uint8_t clock_div_frac8); | ||
|
||
// backwards compatibility | ||
static inline void cyw43_set_pio_clock_divisor(uint16_t clock_div_int, uint8_t clock_div_frac8) { | ||
return cyw43_set_pio_clkdiv_int_frac8(clock_div_int, clock_div_frac8); | ||
} | ||
#endif | ||
|
||
#ifdef __cplusplus | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't see anything in the RP2040 datasheet that implies that this isn't a full 24-bit integer divider? (The only bit that looks odd is that the 24-bit
CLK_GPOUT0_DIV.INT
field says "0 → divide by 2^16")There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(I've started an internal email thread to try and get clarity on this)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Conclusion of this email thread (for any curious onlookers) was that clock-dividers are indeed 24-bit integer, 8-bit fractional (24:8) on RP2040, but 16-bit integer, 16-bit fractional (16:16) on RP2350.
The snippet of the RP2040 datasheet I quoted above is apparently a typo, and setting the
.INT
part of the divider to 0 does a full 2^24 divide.