mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-24 06:07:52 -04:00
Merge branch 'main' into sw_cleanup
This commit is contained in:
commit
ab6bca3bb4
7 changed files with 133 additions and 30 deletions
|
@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
|
|||
|
||||
| Date | Version | Comment | Ticket |
|
||||
|:----:|:-------:|:--------|:------:|
|
||||
| 12.04.2025 | 1.11.2.7 | :sparkles: add PWM polarity configuration | [#1230](https://github.com/stnolting/neorv32/pull/1230) |
|
||||
| 07.04.2025 | 1.11.2.6 | :bug: fix SDI input synchronization | [#1227](https://github.com/stnolting/neorv32/pull/1227) |
|
||||
| 05.04.2025 | 1.11.2.5 | minor rtl edits and optimizations | [#1225](https://github.com/stnolting/neorv32/pull/1225) |
|
||||
| 01.04.2025 | 1.11.2.4 | :bug: fix bug in PWM clock prescaler | [#1222](https://github.com/stnolting/neorv32/pull/1222) |
|
||||
|
|
|
@ -30,13 +30,14 @@ Depending on the configured number channels, the PWM module provides 16 configur
|
|||
be accessed without raising an exception. However, registers above `IO_PWM_NUM_CH-1` are read-only and hardwired to
|
||||
all-zero.
|
||||
|
||||
Each configuration provides a 1-bit enable flag to enable/disable the according channel, an 8-bit register for setting
|
||||
the duty cycle and a 3-bit clock prescaler select as well as a 10-bit clock diver for _coarse_ and _fine_ tuning of the
|
||||
carrier frequency, respectively.
|
||||
Each configuration provides a 1-bit enable flag to enable/disable the according channel, a 1-bit flag for setting the
|
||||
channel polarity, an 8-bit register for setting the duty cycle and a 3-bit clock prescaler select as well as a 10-bit clock
|
||||
diver for _coarse_ and _fine_ tuning of the carrier frequency, respectively.
|
||||
|
||||
A channel is enabled by setting the `PWM_CFG_EN` bit. If this bit is cleared the according PWM output is set to zero.
|
||||
The duty cycle is programmed via the 8 `PWM_CFG_DUTY` bits. Based on the value programmed to this bits the duty cycle
|
||||
the resulting duty cycle of the according channel can be computed by the following formula:
|
||||
A channel is enabled by setting the `PWM_CFG_EN` bit. If this bit is cleared the according PWM output is deasserted
|
||||
(zero if channel polarity is not inverted, one if inverted). The duty cycle is programmed via the 8 `PWM_CFG_DUTY` bits.
|
||||
Based on the value programmed to these bits the resulting duty cycle of the according channel can be computed by the
|
||||
following formula:
|
||||
|
||||
_Duty Cycle_[%] = `PWM_CFG_DUTY` / 2^8^
|
||||
|
||||
|
@ -66,13 +67,15 @@ _f~PWM~_[Hz] = _f~main~_[Hz] / (2^8^ * `clock_prescaler` * (1 + `PWM_CFG_CDIV`))
|
|||
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
|
||||
.5+<| `0xfff00000` .5+<| `CHANNEL_CFG[0]` <|`31` - `PWM_CFG_EN` ^| r/w <| Channel 0: channel enabled when set
|
||||
<|`30:28` - `PWM_CFG_PRSC_MSB:PWM_CFG_PRSC_LSB` ^| r/w <| Channel 0: 3-bit clock prescaler select
|
||||
<|`27:18` ^| r/- <| Channel 0: _reserved_, hardwired to zero
|
||||
<|`27` - `PWM_CFG_POL` ^| r/w <| Channel 0: channel polarity, inverted when set
|
||||
<|`26:18` ^| r/- <| Channel 0: _reserved_, hardwired to zero
|
||||
<|`17:8` - `PWM_CFG_CDIV_MSB:PWM_CFG_CDIV_LSB` ^| r/w <| Channel 0: 10-bit clock divider
|
||||
<|`7:0` - `PWM_CFG_DUTY_MSB:PWM_CFG_DUTY_LSB` ^| r/w <| Channel 0: 8-bit duty cycle
|
||||
| `0xfff00004` ... `0xfff00038` | `CHANNEL_CFG[1]` ... `CHANNEL_CFG[14]` | ... | r/w <| Channels 1 to 14
|
||||
.5+<| `0xfff0003C` .5+<| `CHANNEL_CFG[15]` <|`31` - `PWM_CFG_EN` ^| r/w <| Channel 15: channel enabled when set
|
||||
<|`30:28` - `PWM_CFG_PRSC_MSB:PWM_CFG_PRSC_LSB` ^| r/w <| Channel 15: 3-bit clock prescaler select
|
||||
<|`27:18` ^| r/- <| Channel 15: _reserved_, hardwired to zero
|
||||
<|`27` - `PWM_CFG_POL` ^| r/w <| Channel 15: channel polarity, inverted when set
|
||||
<|`26:18` ^| r/- <| Channel 15: _reserved_, hardwired to zero
|
||||
<|`17:8` - `PWM_CFG_CDIV_MSB:PWM_CFG_CDIV_LSB` ^| r/w <| Channel 15: 10-bit clock divider
|
||||
<|`7:0` - `PWM_CFG_DUTY_MSB:PWM_CFG_DUTY_LSB` ^| r/w <| Channel 15: 8-bit duty cycle
|
||||
|=======================
|
||||
|
|
|
@ -29,7 +29,7 @@ package neorv32_package is
|
|||
|
||||
-- Architecture Constants -----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01110206"; -- hardware version
|
||||
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01110207"; -- hardware version
|
||||
constant archid_c : natural := 19; -- official RISC-V architecture ID
|
||||
constant XLEN : natural := 32; -- native data path width
|
||||
|
||||
|
|
|
@ -158,6 +158,7 @@ architecture neorv32_pwm_channel_rtl of neorv32_pwm_channel is
|
|||
-- configuration register --
|
||||
signal cfg_en : std_ulogic; -- channel enable
|
||||
signal cfg_prsc : std_ulogic_vector(2 downto 0); -- (course) clock prescaler select
|
||||
signal cfg_pol : std_ulogic; -- channel polarity
|
||||
signal cfg_cdiv : std_ulogic_vector(9 downto 0); -- (fine) clock divider
|
||||
signal cfg_duty : std_ulogic_vector(7 downto 0); -- duty cycle
|
||||
|
||||
|
@ -175,12 +176,14 @@ begin
|
|||
if (rstn_i = '0') then
|
||||
cfg_en <= '0';
|
||||
cfg_prsc <= (others => '0');
|
||||
cfg_pol <= '0';
|
||||
cfg_cdiv <= (others => '0');
|
||||
cfg_duty <= (others => '0');
|
||||
elsif rising_edge(clk_i) then
|
||||
if (we_i = '1') then
|
||||
cfg_en <= wdata_i(31);
|
||||
cfg_prsc <= wdata_i(30 downto 28);
|
||||
cfg_pol <= wdata_i(27);
|
||||
cfg_cdiv <= wdata_i(17 downto 8);
|
||||
cfg_duty <= wdata_i(7 downto 0);
|
||||
end if;
|
||||
|
@ -188,7 +191,7 @@ begin
|
|||
end process config_write;
|
||||
|
||||
-- read access --
|
||||
rdata_o <= cfg_en & cfg_prsc & "0000000000" & cfg_cdiv & cfg_duty when (re_i = '1') else (others => '0');
|
||||
rdata_o <= cfg_en & cfg_prsc & cfg_pol & "000000000" & cfg_cdiv & cfg_duty when (re_i = '1') else (others => '0');
|
||||
|
||||
-- enable global clock generator --
|
||||
clkgen_en_o <= cfg_en;
|
||||
|
@ -226,9 +229,9 @@ begin
|
|||
|
||||
-- pwm output --
|
||||
if (cfg_en = '0') or (unsigned(cnt_duty) >= unsigned(cfg_duty)) then
|
||||
pwm_o <= '0';
|
||||
pwm_o <= cfg_pol; -- deasserted
|
||||
else
|
||||
pwm_o <= '1';
|
||||
pwm_o <= not cfg_pol; -- asserted
|
||||
end if;
|
||||
|
||||
end if;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#ifndef NEORV32_PWM_H
|
||||
#define NEORV32_PWM_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
|
@ -36,6 +37,7 @@ enum CHANNEL_CFG_enum {
|
|||
PWM_CFG_CDIV_LSB = 8, /**< PWM configuration register(8) (r/w): Clock divider (10-bit), LSB */
|
||||
PWM_CFG_CDIV_MSB = 17, /**< PWM configuration register(17) (r/w): Clock divider (10-bit), MSB */
|
||||
|
||||
PWM_CFG_POL = 27, /**< PWM configuration register(27) (r/w): Channel polarity, inverted when set */
|
||||
PWM_CFG_PRSC_LSB = 28, /**< PWM configuration register(28) (r/w): Clock prescaler select (3-bit), LSB */
|
||||
PWM_CFG_PRSC_MSB = 30, /**< PWM configuration register(30) (r/w): Clock prescaler select (3-bit), MSB */
|
||||
PWM_CFG_EN = 31 /**< PWM configuration register(31) (r/w): channel enable */
|
||||
|
@ -51,6 +53,7 @@ int neorv32_pwm_available(void);
|
|||
int neorv32_pmw_get_num_channels(void);
|
||||
void neorv32_pwm_ch_enable(int channel);
|
||||
void neorv32_pwm_ch_disable(int channel);
|
||||
void neorv32_pwm_ch_set_polarity(int channel, bool inverted);
|
||||
void neorv32_pwm_ch_set_clock(int channel, int prsc, int cdiv);
|
||||
void neorv32_pwm_ch_set_duty(int channel, int duty);
|
||||
/**@}*/
|
||||
|
|
|
@ -80,6 +80,24 @@ void neorv32_pwm_ch_disable(int channel) {
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
* Set PWM channel's polarity configuration.
|
||||
*
|
||||
* @param[in] channel Channel select (0..15).
|
||||
* @param[in] normal polarity if false (default), inverted polarity if true
|
||||
**************************************************************************/
|
||||
void neorv32_pwm_ch_set_polarity(int channel, bool inverted) {
|
||||
|
||||
channel &= 0xf; // constrain range
|
||||
|
||||
if (inverted) {
|
||||
NEORV32_PWM->CHANNEL_CFG[channel] |= ((uint32_t)(1 << PWM_CFG_POL));
|
||||
} else {
|
||||
NEORV32_PWM->CHANNEL_CFG[channel] &= ~((uint32_t)(1 << PWM_CFG_POL));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
* Set PWM channel's clock configuration.
|
||||
*
|
||||
|
@ -92,7 +110,7 @@ void neorv32_pwm_ch_set_clock(int channel, int prsc, int cdiv) {
|
|||
channel &= 0xf; // constrain range
|
||||
|
||||
uint32_t tmp = NEORV32_PWM->CHANNEL_CFG[channel];
|
||||
tmp &= 0x800000ffU; // clear current prsc and cdiv, keep enable and duty
|
||||
tmp &= 0x880000ffU; // clear current prsc and cdiv, keep enable, polarity, and duty
|
||||
tmp |= ((uint32_t)(prsc & 0x7U)) << PWM_CFG_PRSC_LSB;
|
||||
tmp |= ((uint32_t)(cdiv & 0x3ffU)) << PWM_CFG_CDIV_LSB;
|
||||
NEORV32_PWM->CHANNEL_CFG[channel] = tmp;
|
||||
|
|
|
@ -528,43 +528,118 @@
|
|||
|
||||
<addressBlock>
|
||||
<offset>0</offset>
|
||||
<size>0x10</size>
|
||||
<size>0x40</size>
|
||||
<usage>registers</usage>
|
||||
</addressBlock>
|
||||
|
||||
<registers>
|
||||
<register>
|
||||
<name>CTRL</name>
|
||||
<description>Control register</description>
|
||||
<name>CHANNEL_CFG[0]</name>
|
||||
<description>Channel 0 configuration register</description>
|
||||
<addressOffset>0x00</addressOffset>
|
||||
<fields>
|
||||
<field>
|
||||
<name>PWM_CTRL_EN</name>
|
||||
<bitRange>[0:0]</bitRange>
|
||||
<description>PWM controller enable flag</description>
|
||||
<name>PWM_CFG_DUTY</name>
|
||||
<bitRange>[7:0]</bitRange>
|
||||
<description>Duty cycle</description>
|
||||
</field>
|
||||
<field>
|
||||
<name>PWM_CTRL_PRSCx</name>
|
||||
<bitRange>[3:1]</bitRange>
|
||||
<name>PWM_CFG_CDIV</name>
|
||||
<bitRange>[17:8]</bitRange>
|
||||
<description>Clock divider</description>
|
||||
</field>
|
||||
<field>
|
||||
<name>PWM_CFG_POL</name>
|
||||
<bitRange>[27:27]</bitRange>
|
||||
<description>Channel polarity, inverted when set</description>
|
||||
</field>
|
||||
<field>
|
||||
<name>PWM_CFG_PRSC</name>
|
||||
<bitRange>[30:28]</bitRange>
|
||||
<description>Clock prescaler select</description>
|
||||
</field>
|
||||
<field>
|
||||
<name>PWM_CFG_EN</name>
|
||||
<bitRange>[31:31]</bitRange>
|
||||
<description>Channel enable</description>
|
||||
</field>
|
||||
</fields>
|
||||
</register>
|
||||
<register>
|
||||
<name>DC[0]</name>
|
||||
<description>Duty cycle register 0</description>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[1]</name>
|
||||
<description>Channel 1 configuration register</description>
|
||||
<addressOffset>0x04</addressOffset>
|
||||
</register>
|
||||
<register>
|
||||
<name>DC[1]</name>
|
||||
<description>Duty cycle register 1</description>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[2]</name>
|
||||
<description>Channel 2 configuration register</description>
|
||||
<addressOffset>0x08</addressOffset>
|
||||
</register>
|
||||
<register>
|
||||
<name>DC[2]</name>
|
||||
<description>Duty cycle register 2</description>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[3]</name>
|
||||
<description>Channel 3 configuration register</description>
|
||||
<addressOffset>0x0C</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[4]</name>
|
||||
<description>Channel 4 configuration register</description>
|
||||
<addressOffset>0x10</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[5]</name>
|
||||
<description>Channel 5 configuration register</description>
|
||||
<addressOffset>0x14</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[6]</name>
|
||||
<description>Channel 6 configuration register</description>
|
||||
<addressOffset>0x18</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[7]</name>
|
||||
<description>Channel 7 configuration register</description>
|
||||
<addressOffset>0x1C</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[8]</name>
|
||||
<description>Channel 8 configuration register</description>
|
||||
<addressOffset>0x20</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[9]</name>
|
||||
<description>Channel 9 configuration register</description>
|
||||
<addressOffset>0x24</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[10]</name>
|
||||
<description>Channel 10 configuration register</description>
|
||||
<addressOffset>0x28</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[11]</name>
|
||||
<description>Channel 11 configuration register</description>
|
||||
<addressOffset>0x2C</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[12]</name>
|
||||
<description>Channel 12 configuration register</description>
|
||||
<addressOffset>0x30</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[13]</name>
|
||||
<description>Channel 13 configuration register</description>
|
||||
<addressOffset>0x34</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[14]</name>
|
||||
<description>Channel 14 configuration register</description>
|
||||
<addressOffset>0x38</addressOffset>
|
||||
</register>
|
||||
<register derivedFrom="CHANNEL_CFG[0]">
|
||||
<name>CHANNEL_CFG[15]</name>
|
||||
<description>Channel 15 configuration register</description>
|
||||
<addressOffset>0x3C</addressOffset>
|
||||
</register>
|
||||
</registers>
|
||||
</peripheral>
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue