mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-24 14:17:51 -04:00
[docs] update PWM sections
This commit is contained in:
parent
25418bcbab
commit
fcc08ac579
2 changed files with 41 additions and 46 deletions
|
@ -20,7 +20,8 @@ image::neorv32_processor.png[align=center]
|
|||
**Key Features**
|
||||
|
||||
* _optional_ processor-internal data and instruction memories (<<_data_memory_dmem,**DMEM**>>/<<_instruction_memory_imem,**IMEM**>>)
|
||||
* _optional_ caches (<<_processor_internal_instruction_cache_icache,**iCACHE**>>, <<_processor_internal_data_cache_dcache,**dCACHE**>>, <<_execute_in_place_module_xip,**xipCACHE**>>, <<_processor_external_bus_interface_xbus,**xCACHE**>>)
|
||||
* _optional_ caches (<<_processor_internal_instruction_cache_icache,**I-CACHE**>>, <<_processor_internal_data_cache_dcache,**D-CACHE**>>,
|
||||
<<_execute_in_place_module_xip,**XIP-CACHE**>>, <<_processor_external_bus_interface_xbus,**XBUS-CACHE**>>)
|
||||
* _optional_ internal bootloader (<<_bootloader_rom_bootrom,**BOOTROM**>>) with UART console & SPI flash boot option
|
||||
* _optional_ machine system timer (<<_machine_system_timer_mtime,**MTIME**>>), RISC-V-compatible
|
||||
* _optional_ two independent universal asynchronous receivers and transmitters (<<_primary_universal_asynchronous_receiver_and_transmitter_uart0,**UART0**>>,
|
||||
|
@ -31,11 +32,11 @@ image::neorv32_processor.png[align=center]
|
|||
* _optional_ general purpose parallel IO port (<<_general_purpose_input_and_output_port_gpio,**GPIO**>>), 64xOut, 64xIn
|
||||
* _optional_ 32-bit external bus interface, Wishbone b4 / AXI4-Lite compatible (<<_processor_external_bus_interface_xbus,**XBUS**>>)
|
||||
* _optional_ watchdog timer (<<_watchdog_timer_wdt,**WDT**>>)
|
||||
* _optional_ PWM controller with up to 12 channels & 8-bit duty cycle resolution (<<_pulse_width_modulation_controller_pwm,**PWM**>>)
|
||||
* _optional_ PWM controller with up to 16 individual channels (<<_pulse_width_modulation_controller_pwm,**PWM**>>)
|
||||
* _optional_ ring-oscillator-based true random number generator (<<_true_random_number_generator_trng,**TRNG**>>)
|
||||
* _optional_ custom functions subsystem for custom co-processor extensions (<<_custom_functions_subsystem_cfs,**CFS**>>)
|
||||
* _optional_ NeoPixel(TM)/WS2812-compatible smart LED interface (<<_smart_led_interface_neoled,**NEOLED**>>)
|
||||
* _optional_ external interrupt controller with up to 32 channels (<<_external_interrupt_controller_xirq,**XIRQ**>>)
|
||||
* _optional_ external interrupt controller with up to 32 channels and programmable interrupt triggers (<<_external_interrupt_controller_xirq,**XIRQ**>>)
|
||||
* _optional_ general purpose 32-bit timer (<<_general_purpose_timer_gptmr,**GPTMR**>>)
|
||||
* _optional_ execute in-place module (<<_execute_in_place_module_xip,**XIP**>>)
|
||||
* _optional_ 1-wire serial interface controller (<<_one_wire_serial_interface_controller_onewire,**ONEWIRE**>>), compatible to the 1-wire standard
|
||||
|
@ -43,7 +44,7 @@ image::neorv32_processor.png[align=center]
|
|||
* _optional_ stream link interface (<<_stream_link_interface_slink,**SLINK**>>), AXI4-Stream compatible
|
||||
* _optional_ cyclic redundancy check unit (<<_cyclic_redundancy_check_crc,**CRC**>>)
|
||||
* _optional_ on-chip debugger with JTAG TAP (<<_on_chip_debugger_ocd,**OCD**>>)
|
||||
* (optional) system configuration information memory to check HW configuration via software (<<_system_configuration_information_memory_sysinfo,**SYSINFO**>>)
|
||||
* _optional_ system configuration information memory to determine hardware configuration via software (<<_system_configuration_information_memory_sysinfo,**SYSINFO**>>)
|
||||
|
||||
|
||||
<<<
|
||||
|
@ -72,7 +73,7 @@ bits/channels are hardwired to zero.
|
|||
Some interfaces (like the TWI and the 1-Wire bus) require explicit tri-state drivers in the final top module.
|
||||
|
||||
.Input/Output Registers
|
||||
[NOTE]
|
||||
[NOTE]
|
||||
By default all output signals are driven by register and all input signals are synchronized into the processor's
|
||||
clock domain also using registers. However, for ASIC implementations it is recommended to add another register state
|
||||
to all inputs and output so the synthesis tool can insert an explicit IO (boundary) scan chain.
|
||||
|
@ -149,7 +150,7 @@ to all inputs and output so the synthesis tool can insert an explicit IO (bounda
|
|||
| `onewire_i` | 1 | in | `'H'` | 1-wire bus sense input
|
||||
| `onewire_o` | 1 | out | - | 1-wire bus output (pull low only)
|
||||
5+^| **<<_pulse_width_modulation_controller_pwm>>**
|
||||
| `pwm_o` | 12 | out | - | pulse-width modulated channels
|
||||
| `pwm_o` | 16 | out | - | pulse-width modulated channels
|
||||
5+^| **<<_custom_functions_subsystem_cfs>>**
|
||||
| `cfs_in_i` | 32 | in | `'L'` | custom CFS input signal conduit
|
||||
| `cfs_out_o` | 32 | out | - | custom CFS output signal conduit
|
||||
|
@ -289,7 +290,7 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt
|
|||
| `IO_SDI_FIFO` | natural | 1 | Depth of the <<_serial_data_interface_controller_sdi>> FIFO. Has to be a power of two, min 1, max 32768.
|
||||
| `IO_TWI_EN` | boolean | false | Implement the <<_two_wire_serial_interface_controller_twi>>.
|
||||
| `IO_TWI_FIFO` | natural | 1 | Depth of the <<_two_wire_serial_interface_controller_twi>> FIFO. Has to be a power of two, min 1, max 32768.
|
||||
| `IO_PWM_NUM_CH` | natural | 0 | Number of channels of the <<_pulse_width_modulation_controller_pwm>> to implement (0..12).
|
||||
| `IO_PWM_NUM_CH` | natural | 0 | Number of channels of the <<_pulse_width_modulation_controller_pwm>> to implement (0..16).
|
||||
| `IO_WDT_EN` | boolean | false | Implement the <<_watchdog_timer_wdt>>.
|
||||
| `IO_TRNG_EN` | boolean | false | Implement the <<_true_random_number_generator_trng>>.
|
||||
| `IO_TRNG_FIFO` | natural | 1 | Depth of the TRNG data FIFO. Has to be a power of two, min 1, max 32768.
|
||||
|
@ -585,7 +586,7 @@ explicit specific processor generic. See section <<_processor_external_bus_inter
|
|||
==== Reservation Set Controller
|
||||
|
||||
The reservation set controller is responsible for handling the load-reservate and store-conditional bus transaction that
|
||||
are triggered by the `lr.w` (LR) and `sc.w` (SC) instructions from the CPU's <<_a_isa_extension>>.
|
||||
are triggered by the `lr.w` (LR) and `sc.w` (SC) instructions from the CPU's <<_zalrsc_isa_extension>>.
|
||||
|
||||
A "reservation" defines an address or address range that provides a guarding mechanism to support atomic accesses. A new
|
||||
reservation is registered by the LR instruction. The address provided by this instruction defines the memory location
|
||||
|
|
|
@ -17,47 +17,45 @@
|
|||
|
||||
**Overview**
|
||||
|
||||
The PWM module implements a pulse-width modulation controller with up to 12 independent channels providing
|
||||
8-bit resolution per channel. The actual number of implemented channels is defined by the `IO_PWM_NUM_CH` generic.
|
||||
Setting this generic to zero will completely remove the PWM controller from the design.
|
||||
|
||||
[NOTE]
|
||||
The `pwm_o` has a static size of 12-bit. If less than 12 PWM channels are configured, only the LSB-aligned channel
|
||||
bits are used while the remaining bits are hardwired to zero.
|
||||
The PWM module implements a pulse-width modulation controller with up to 16 independent channels. Duty cycle and
|
||||
carrier frequency can be programmed individually for each channel.The total number of implemented channels is
|
||||
defined by the `IO_PWM_NUM_CH` generic. The PWM output signal `pwm_o` has a static size of 16-bit. Channel 0
|
||||
corresponds to bit 0, channel 1 to bit 1 and so on. If less than 16 channels are configured, only the LSB-aligned
|
||||
channel bits are connected while the remaining ones are hardwired to zero.
|
||||
|
||||
|
||||
**Theory of Operation**
|
||||
|
||||
The PWM controller is activated by setting the `PWM_CTRL_EN` bit in the module's control register `CTRL`. When this
|
||||
bit is cleared, the unit is reset and all PWM output channels are set to zero. The module
|
||||
provides three duty cycle registers `DC[0]` to `DC[2]`. Each register contains the duty cycle configuration for four
|
||||
consecutive channels. For example, the duty cycle of channel 0 is defined via bits 7:0 in `DC[0]`. The duty cycle of
|
||||
channel 2 is defined via bits 15:0 in `DC[0]` and so on.
|
||||
Depending on the configured number channels, the PWM module provides 16 configuration registers `CHANNEL_CFG[0]` to
|
||||
`CHANNEL_CFG[15]` - one for each channel. Regardless of the configuration of `IO_PWM_NUM_CH` all channel registers can
|
||||
be accessed without raising an exception. However, registers above `IO_PWM_NUM_CH-1` are read-only and hardwired to
|
||||
all-zero.
|
||||
|
||||
[NOTE]
|
||||
Regardless of the configuration of `IO_PWM_NUM_CH` all module registers can be accessed without raising an exception.
|
||||
Software can discover the number of available channels by writing 0xff to all duty cycle configuration bytes and
|
||||
reading those values back. The duty-cycle of channels that were not implemented always reads as 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.
|
||||
|
||||
Based on the configured duty cycle the according intensity of the 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 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:
|
||||
|
||||
_**Intensity~x~**_ = `DC[y](i*8+7 downto i*8)` / (2^8^)
|
||||
_Duty Cycle_[%] = `PWM_CFG_DUTY` / 2^8^
|
||||
|
||||
The base frequency of the generated PWM signals is defined by the PWM core clock. This clock is derived
|
||||
from the main processor clock and divided by a prescaler via the 3-bit `PWM_CTRL_PRSCx` in the unit's control
|
||||
register.
|
||||
The PWM period (carrier frequency) is derived from the processor's main clock (_f~main~_). The `PWM_CFG_PRSC` register
|
||||
bits allow to select one out of eight pre-defined clock prescalers for a coarse clock scaling. The 10 `PWM_CFG_CDIV` register
|
||||
bits can be used to apply another fine clock scaling.
|
||||
|
||||
.PWM prescaler configuration
|
||||
[cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"]
|
||||
[options="header",grid="rows"]
|
||||
|=======================
|
||||
| **`PWM_CTRL_PRSCx`** | `0b000` | `0b001` | `0b010` | `0b011` | `0b100` | `0b101` | `0b110` | `0b111`
|
||||
| **`PWM_CFG_PRSC`** | `0b000` | `0b001` | `0b010` | `0b011` | `0b100` | `0b101` | `0b110` | `0b111`
|
||||
| Resulting `clock_prescaler` | 2 | 4 | 8 | 64 | 128 | 1024 | 2048 | 4096
|
||||
|=======================
|
||||
|
||||
The resulting PWM carrier frequency is defined by:
|
||||
|
||||
_**f~PWM~**_ = _f~main~[Hz]_ / (2^8^ * `clock_prescaler`)
|
||||
_f~PWM~_[Hz] = _f~main~_[Hz] / (2^8^ * `clock_prescaler` * (1 + `PWM_CFG_CDIV`))
|
||||
|
||||
|
||||
**Register Map**
|
||||
|
@ -67,19 +65,15 @@ _**f~PWM~**_ = _f~main~[Hz]_ / (2^8^ * `clock_prescaler`)
|
|||
[options="header",grid="all"]
|
||||
|=======================
|
||||
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
|
||||
.3+<| `0xfffff000` .3+<| `CTRL` <|`0` `PWM_CTRL_EN` ^| r/w <| PWM enable
|
||||
<|`3:1` `PWM_CTRL_PRSC2 : PWM_CTRL_PRSC0` ^| r/w <| 3-bit clock prescaler select
|
||||
<|`31:4` - ^| r/- <| _reserved_, read as zero
|
||||
.4+<| `0xfffff004` .4+<| `DC[0]` <|`7:0` ^| r/w <| 8-bit duty cycle for channel 0
|
||||
<|`15:8` ^| r/w <| 8-bit duty cycle for channel 1
|
||||
<|`23:16` ^| r/w <| 8-bit duty cycle for channel 2
|
||||
<|`31:24` ^| r/w <| 8-bit duty cycle for channel 3
|
||||
.4+<| `0xfffff008` .4+<| `DC[1]` <|`7:0` ^| r/w <| 8-bit duty cycle for channel 4
|
||||
<|`15:8` ^| r/w <| 8-bit duty cycle for channel 5
|
||||
<|`23:16` ^| r/w <| 8-bit duty cycle for channel 6
|
||||
<|`31:24` ^| r/w <| 8-bit duty cycle for channel 7
|
||||
.4+<| `0xfffff00c` .4+<| `DC[2]` <|`7:0` ^| r/w <| 8-bit duty cycle for channel 8
|
||||
<|`15:8` ^| r/w <| 8-bit duty cycle for channel 9
|
||||
<|`23:16` ^| r/w <| 8-bit duty cycle for channel 10
|
||||
<|`31:24` ^| r/w <| 8-bit duty cycle for channel 11
|
||||
.5+<| `0xfffff000` .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
|
||||
<|`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
|
||||
| `0xfffff004` ... `0xfffff038` | `CHANNEL_CFG[1]` ... `CHANNEL_CFG[14]` | ... | r/w <| Channels 1 to 14
|
||||
.5+<| `0xfffff03C` .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
|
||||
<|`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
|
||||
|=======================
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue