From 2ec35f60ca6866551309f74aba5c157970e8925a Mon Sep 17 00:00:00 2001 From: krzychb Date: Mon, 20 Nov 2017 04:51:30 +0100 Subject: [PATCH] RMT API docs update, new example --- components/driver/include/driver/rmt.h | 187 ++++++------------ docs/api-reference/peripherals/rmt.rst | 159 ++++++++++++++- examples/peripherals/rmt_tx/Makefile | 9 + examples/peripherals/rmt_tx/README.md | 25 +++ examples/peripherals/rmt_tx/main/component.mk | 4 + .../peripherals/rmt_tx/main/rmt_tx_main.c | 119 +++++++++++ 6 files changed, 374 insertions(+), 129 deletions(-) create mode 100644 examples/peripherals/rmt_tx/Makefile create mode 100644 examples/peripherals/rmt_tx/README.md create mode 100644 examples/peripherals/rmt_tx/main/component.mk create mode 100644 examples/peripherals/rmt_tx/main/rmt_tx_main.c diff --git a/components/driver/include/driver/rmt.h b/components/driver/include/driver/rmt.h index 56c5ed4952..79ac0e5d67 100644 --- a/components/driver/include/driver/rmt.h +++ b/components/driver/include/driver/rmt.h @@ -33,14 +33,14 @@ extern "C" { #define RMT_MEM_ITEM_NUM (RMT_MEM_BLOCK_BYTE_NUM/4) typedef enum { - RMT_CHANNEL_0=0, /*!< RMT Channel0 */ - RMT_CHANNEL_1, /*!< RMT Channel1 */ - RMT_CHANNEL_2, /*!< RMT Channel2 */ - RMT_CHANNEL_3, /*!< RMT Channel3 */ - RMT_CHANNEL_4, /*!< RMT Channel4 */ - RMT_CHANNEL_5, /*!< RMT Channel5 */ - RMT_CHANNEL_6, /*!< RMT Channel6 */ - RMT_CHANNEL_7, /*!< RMT Channel7 */ + RMT_CHANNEL_0 = 0, /*!< RMT Channel 0 */ + RMT_CHANNEL_1, /*!< RMT Channel 1 */ + RMT_CHANNEL_2, /*!< RMT Channel 2 */ + RMT_CHANNEL_3, /*!< RMT Channel 3 */ + RMT_CHANNEL_4, /*!< RMT Channel 4 */ + RMT_CHANNEL_5, /*!< RMT Channel 5 */ + RMT_CHANNEL_6, /*!< RMT Channel 6 */ + RMT_CHANNEL_7, /*!< RMT Channel 7 */ RMT_CHANNEL_MAX } rmt_channel_t; @@ -51,7 +51,7 @@ typedef enum { }rmt_mem_owner_t; typedef enum { - RMT_BASECLK_REF = 0, /*!< RMT source clock system reference tick, 1MHz by default(Not supported in this version) */ + RMT_BASECLK_REF = 0, /*!< RMT source clock system reference tick, 1MHz by default (not supported in this version) */ RMT_BASECLK_APB, /*!< RMT source clock is APB CLK, 80Mhz by default */ RMT_BASECLK_MAX, } rmt_source_clk_t; @@ -63,20 +63,20 @@ typedef enum { } rmt_data_mode_t; typedef enum { - RMT_MODE_TX=0, /*!< RMT TX mode */ - RMT_MODE_RX, /*!< RMT RX mode */ + RMT_MODE_TX = 0, /*!< RMT TX mode */ + RMT_MODE_RX, /*!< RMT RX mode */ RMT_MODE_MAX } rmt_mode_t; typedef enum { - RMT_IDLE_LEVEL_LOW=0, /*!< RMT TX idle level: low Level */ - RMT_IDLE_LEVEL_HIGH, /*!< RMT TX idle level: high Level */ + RMT_IDLE_LEVEL_LOW = 0, /*!< RMT TX idle level: low Level */ + RMT_IDLE_LEVEL_HIGH, /*!< RMT TX idle level: high Level */ RMT_IDLE_LEVEL_MAX, } rmt_idle_level_t; typedef enum { - RMT_CARRIER_LEVEL_LOW=0, /*!< RMT carrier wave is modulated for low Level output */ - RMT_CARRIER_LEVEL_HIGH, /*!< RMT carrier wave is modulated for high Level output */ + RMT_CARRIER_LEVEL_LOW = 0, /*!< RMT carrier wave is modulated for low Level output */ + RMT_CARRIER_LEVEL_HIGH, /*!< RMT carrier wave is modulated for high Level output */ RMT_CARRIER_LEVEL_MAX } rmt_carrier_level_t; @@ -84,21 +84,21 @@ typedef enum { * @brief Data struct of RMT TX configure parameters */ typedef struct { - bool loop_en; /*!< RMT loop output mode*/ + bool loop_en; /*!< Enable sending RMT items in a loop */ uint32_t carrier_freq_hz; /*!< RMT carrier frequency */ uint8_t carrier_duty_percent; /*!< RMT carrier duty (%) */ - rmt_carrier_level_t carrier_level; /*!< RMT carrier level */ + rmt_carrier_level_t carrier_level; /*!< Level of the RMT output, when the carrier is applied */ bool carrier_en; /*!< RMT carrier enable */ rmt_idle_level_t idle_level; /*!< RMT idle level */ - bool idle_output_en; /*!< RMT idle level output enable*/ + bool idle_output_en; /*!< RMT idle level output enable */ }rmt_tx_config_t; /** * @brief Data struct of RMT RX configure parameters */ typedef struct { - bool filter_en; /*!< RMT receiver filer enable*/ - uint8_t filter_ticks_thresh; /*!< RMT filter tick number */ + bool filter_en; /*!< RMT receiver filter enable */ + uint8_t filter_ticks_thresh; /*!< RMT filter tick number */ uint16_t idle_threshold; /*!< RMT RX idle threshold */ }rmt_rx_config_t; @@ -186,14 +186,16 @@ esp_err_t rmt_get_rx_idle_thresh(rmt_channel_t channel, uint16_t *thresh); * The 8 channels share a 512x32-bit RAM block which can be read and written * by the processor cores over the APB bus, as well as read by the transmitters * and written by the receivers. + * * The RAM address range for channel n is start_addr_CHn to end_addr_CHn, which are defined by: * Memory block start address is RMT_CHANNEL_MEM(n) (in soc/rmt_reg.h), * that is, start_addr_chn = RMT base address + 0x800 + 64 ∗ 4 ∗ n, and * end_addr_chn = RMT base address + 0x800 + 64 ∗ 4 ∗ n + 64 ∗ 4 ∗ RMT_MEM_SIZE_CHn mod 512 ∗ 4 + * * @note * If memory block number of one channel is set to a value greater than 1, this channel will occupy the memory * block of the next channel. - * Channel0 can use at most 8 blocks of memory, accordingly channel7 can only use one memory block. + * Channel 0 can use at most 8 blocks of memory, accordingly channel 7 can only use one memory block. * * @param channel RMT channel (0-7) * @@ -232,11 +234,9 @@ esp_err_t rmt_get_mem_block_num(rmt_channel_t channel, uint8_t* rmt_mem_num); * * @param low_level Low level duration of carrier. * - * @param carrier_level Configure the way carrier wave is modulated for channel0-7. - * - * 1'b1:transmit on low output level - * - * 1'b0:transmit on high output level + * @param carrier_level Configure the way carrier wave is modulated for channel 0-7. + * - 1'b1:transmit on low output level + * - 1'b0:transmit on high output level * * @return * - ESP_ERR_INVALID_ARG Parameter error @@ -278,7 +278,7 @@ esp_err_t rmt_get_mem_pd(rmt_channel_t channel, bool* pd_en); * @param channel RMT channel (0-7) * * @param tx_idx_rst Set true to reset memory index for TX. - * Otherwise, transmitter will continue sending from the last index in memory. + * Otherwise, transmitter will continue sending from the last index in memory. * * @return * - ESP_ERR_INVALID_ARG Parameter error @@ -364,10 +364,9 @@ esp_err_t rmt_get_memory_owner(rmt_channel_t channel, rmt_mem_owner_t* owner); * * @param channel RMT channel (0-7) * - * @param loop_en To enable RMT transmitter loop sending mode. - * + * @param loop_en Enable RMT transmitter loop sending mode. * If set true, transmitter will continue sending from the first data - * to the last data in channel0-7 again and again. + * to the last data in channel 0-7 over and over again in a loop. * * @return * - ESP_ERR_INVALID_ARG Parameter error @@ -391,7 +390,7 @@ esp_err_t rmt_get_tx_loop_mode(rmt_channel_t channel, bool* loop_en); /** * @brief Set RMT RX filter. * - * In receive mode, channel0-7 will ignore input pulse when the pulse width is smaller than threshold. + * In receive mode, channel 0-7 will ignore input pulse when the pulse width is smaller than threshold. * Counted in source clock, not divided counter clock. * * @param channel RMT channel (0-7) @@ -409,9 +408,9 @@ esp_err_t rmt_set_rx_filter(rmt_channel_t channel, bool rx_filter_en, uint8_t th /** * @brief Set RMT source clock * - * RMT module has two source clock: + * RMT module has two clock sources: * 1. APB clock which is 80Mhz - * 2. REF tick clock, which would be 1Mhz( not supported in this version). + * 2. REF tick clock, which would be 1Mhz (not supported in this version). * * @param channel RMT channel (0-7) * @@ -426,9 +425,9 @@ esp_err_t rmt_set_source_clk(rmt_channel_t channel, rmt_source_clk_t base_clk); /** * @brief Get RMT source clock * - * RMT module has two source clock: + * RMT module has two clock sources: * 1. APB clock which is 80Mhz - * 2. REF tick clock, which would be 1Mhz( not supported in this version). + * 2. REF tick clock, which would be 1Mhz (not supported in this version). * * @param channel RMT channel (0-7) * @@ -447,7 +446,7 @@ esp_err_t rmt_get_source_clk(rmt_channel_t channel, rmt_source_clk_t* src_clk); * * @param idle_out_en To enable idle level output. * - * @param level To set the output signal's level for channel0-7 in idle state. + * @param level To set the output signal's level for channel 0-7 in idle state. * * @return * - ESP_ERR_INVALID_ARG Parameter error @@ -526,7 +525,7 @@ esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en); /** * @brief Set RMT TX threshold event interrupt enable * - * Causes an interrupt when a threshold number of items have been transmitted. + * An interrupt will be triggered when the number of transmitted items reaches the threshold value * * @param channel RMT channel (0 - 7) * @@ -541,7 +540,7 @@ esp_err_t rmt_set_tx_intr_en(rmt_channel_t channel, bool en); esp_err_t rmt_set_tx_thr_intr_en(rmt_channel_t channel, bool en, uint16_t evt_thresh); /** - * @brief Set RMT pins + * @brief Set RMT pin * * @param channel RMT channel (0 - 7) * @@ -558,7 +557,7 @@ esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_nu /** * @brief Configure RMT parameters * - * @param rmt_param RMT parameter structor + * @param rmt_param RMT parameter struct * * @return * - ESP_ERR_INVALID_ARG Parameter error @@ -567,17 +566,18 @@ esp_err_t rmt_set_pin(rmt_channel_t channel, rmt_mode_t mode, gpio_num_t gpio_nu esp_err_t rmt_config(const rmt_config_t* rmt_param); /** - * @brief register RMT interrupt handler, the handler is an ISR. + * @brief Register RMT interrupt handler, the handler is an ISR. * - * The handler will be attached to the same CPU core that this function is running on. - * @note If you already called rmt_driver_install to use system RMT driver, - * please do not register ISR handler again. + * The handler will be attached to the same CPU core that this function is running on. + * + * @note If you already called rmt_driver_install to use system RMT driver, + * please do not register ISR handler again. * * @param fn Interrupt handler function. - * @param arg Parameter for handler function - * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) - * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. - * @param handle If non-zero, a handle to later clean up the ISR gets stored here. + * @param arg Parameter for the handler function + * @param intr_alloc_flags Flags used to allocate the interrupt. One or multiple (ORred) + * ESP_INTR_FLAG_* values. See esp_intr_alloc.h for more info. + * @param handle If non-zero, a handle to later clean up the ISR gets stored here. * * @return * - ESP_OK Success @@ -653,18 +653,18 @@ esp_err_t rmt_driver_uninstall(rmt_channel_t channel); * * @param item_num RMT data item number. * - * @param wait_tx_done If set 1, it will block the task and wait for sending done. + * @param wait_tx_done + * - If set 1, it will block the task and wait for sending done. + * - If set 0, it will not wait and return immediately. * - * If set 0, it will not wait and return immediately. - * - * @note - * This function will not copy data, instead, it will point to the original items, - * and send the waveform items. - * If wait_tx_done is set to true, this function will block and will not return until - * all items have been sent out. - * If wait_tx_done is set to false, this function will return immediately, and the driver - * interrupt will continue sending the items. We must make sure the item data will not be - * damaged when the driver is still sending items in driver interrupt. + * @note + * This function will not copy data, instead, it will point to the original items, + * and send the waveform items. + * If wait_tx_done is set to true, this function will block and will not return until + * all items have been sent out. + * If wait_tx_done is set to false, this function will return immediately, and the driver + * interrupt will continue sending the items. We must make sure the item data will not be + * damaged when the driver is still sending items in driver interrupt. * * @return * - ESP_ERR_INVALID_ARG Parameter error @@ -677,24 +677,24 @@ esp_err_t rmt_write_items(rmt_channel_t channel, const rmt_item32_t* rmt_item, i * * @param channel RMT channel (0 - 7) * - * @param wait_time Maximum time to wait for transmission to be complete + * @param wait_time Maximum time in ticks to wait for transmission to be complete * * @return * - ESP_OK RMT Tx done successfully - * - ESP_ERR_TIMEOUT Crossed the 'wait_time' given + * - ESP_ERR_TIMEOUT Exceeded the 'wait_time' given * - ESP_ERR_INVALID_ARG Parameter error * - ESP_FAIL Driver not installed */ esp_err_t rmt_wait_tx_done(rmt_channel_t channel, TickType_t wait_time); /** - * @brief Get ringbuffer from UART. + * @brief Get ringbuffer from RMT. * - * Users can get the RMT RX ringbuffer handler, and process the RX data. + * Users can get the RMT RX ringbuffer handle, and process the RX data. * * @param channel RMT channel (0 - 7) * - * @param buf_handle Pointer to buffer handler to accept RX ringbuffer handler. + * @param buf_handle Pointer to buffer handle to accept RX ringbuffer handle. * * @return * - ESP_ERR_INVALID_ARG Parameter error @@ -702,62 +702,7 @@ esp_err_t rmt_wait_tx_done(rmt_channel_t channel, TickType_t wait_time); */ esp_err_t rmt_get_ringbuf_handle(rmt_channel_t channel, RingbufHandle_t* buf_handle); -/***************************EXAMPLE********************************** - * - * @note - * You can also refer to example/09_rmt_nec_tx_rx to have more information about how to use RMT module. - * - * ----------------EXAMPLE OF RMT SETTING --------------------- - * @code{c} - * //1. enable RMT - * //enable RMT module, or you can not set any register of it. - * //this will be done in rmt_config API. - * periph_module_enable(PERIPH_RMT_MODULE); - * @endcode - * - * @code{c} - * //2. set RMT transmitter - * void rmt_tx_init() - * { - * rmt_config_t rmt_tx; - * rmt_tx.channel = 0; - * rmt_tx.gpio_num = 16; - * rmt_tx.mem_block_num = 1; - * rmt_tx.clk_div = 100; - * rmt_tx.tx_config.loop_en = false; - * rmt_tx.tx_config.carrier_duty_percent = 50; - * rmt_tx.tx_config.carrier_freq_hz = 38000; - * rmt_tx.tx_config.carrier_level = 1; - * rmt_tx.tx_config.carrier_en = RMT_TX_CARRIER_EN; - * rmt_tx.tx_config.idle_level = 0; - * rmt_tx.tx_config.idle_output_en = true; - * rmt_tx.rmt_mode = 0; - * rmt_config(&rmt_tx); - * - * //install system RMT driver, disable rx ringbuffer for transmitter. - * rmt_driver_install(rmt_tx.channel, 0, 0); - * } - * - * @endcode - * @code{c} - * //3. set RMT receiver - * void rmt_rx_init() - * { - * rmt_config_t rmt_rx; - * rmt_rx.channel = 1; - * rmt_rx.gpio_num = 19; - * rmt_rx.clk_div = 100; - * rmt_rx.mem_block_num = 1; - * rmt_rx.rmt_mode = RMT_MODE_RX; - * rmt_rx.rx_config.filter_en = true; - * rmt_rx.rx_config.filter_ticks_thresh = 100; - * rmt_rx.rx_config.idle_threshold = 0xffff; - * rmt_config(&rmt_rx); - * - * //install system RMT driver. - * rmt_driver_install(rmt_rx.channel, 1000, 0); - * } - * +/* * ----------------EXAMPLE OF RMT INTERRUPT ------------------ * @code{c} * @@ -774,7 +719,7 @@ esp_err_t rmt_get_ringbuf_handle(rmt_channel_t channel, RingbufHandle_t* buf_han * //read RMT interrupt status. * uint32_t intr_st = RMT.int_st.val; * - * //you will find which channels have triggered fade_end interrupt here, + * //you will find which channels have triggered an interrupt here, * //then, you can post some event to RTOS queue to process the event. * //later we will add a queue in the driver code. * @@ -788,8 +733,6 @@ esp_err_t rmt_get_ringbuf_handle(rmt_channel_t channel, RingbufHandle_t* buf_han - - #ifdef __cplusplus } #endif diff --git a/docs/api-reference/peripherals/rmt.rst b/docs/api-reference/peripherals/rmt.rst index 5097a5f0e5..7d16efd8de 100644 --- a/docs/api-reference/peripherals/rmt.rst +++ b/docs/api-reference/peripherals/rmt.rst @@ -1,15 +1,160 @@ RMT -======== +=== -Overview --------- +The RMT (Remote Control) module driver can be used to send and receive infrared remote control signals. Due to flexibility of RMT module, the driver can also be used to generate or receive many other types of signals. -The RMT (Remote Control) module driver can be used to send and receive infrared remote control signals. Due to flexibility of RMT module, the driver can also be used to generate many other types of signals. +There couple of typical steps to setup and operate the RMT and they are discussed in the following sections: -Application Example -------------------- +1. `Configure Driver`_ +2. `Transmit Data`_ or `Receive Data`_ +3. `Change Operation Parameters`_ +4. `Use Interrupts`_ + +The RMT has eight channels numbered from zero to seven. Each channel is able to independently transmit or receive data. They are refereed to using indexes defined in structure :cpp:type:`rmt_channel_t`. + + +Configure Driver +---------------- + +There are several parameters that define how particular channel operates. Most of these parameters are configured by setting specific members of :cpp:type:`rmt_config_t` structure. Some of the parameters are common to both transmit or receive mode, and some are mode specific. They are all discussed below. + + +Common Parameters +^^^^^^^^^^^^^^^^^ + +* The **channel** that to be configured to be configured, select one from the :cpp:type:`rmt_channel_t` enumerator. +* The RMT **operation mode** - whether this channel is used to transmit or receive data, selected by setting a **rmt_mode** members to one of the values from :cpp:type:`rmt_mode_t`. +* What is the **pin number** to transmit or receive RMT signals, selected by setting **gpio_num**. +* How many **memory blocks** will be used by the channel, set with **mem_block_num**. +* A **clock divider**, that will determine the range of pulse length generated by the RMT transmitter or discriminated by the receiver. Selected by setting **clk_div** to a value within [1 .. 255] range. The RMT source clock is typically APB CLK, 80Mhz by default. + +.. note:: + + The period of a square valve after the clock divider is called a 'tick'. The length the pulses generated by the RMT transmitter or discriminated by the receiver is configured in number of 'ticks'. + +There are also couple of specific parameters that should be set up depending if selected channel is configured in `Transmit Mode`_ or `Receive Mode`_: + + +Transmit Mode +^^^^^^^^^^^^^ + +When configuring channel in transmit mode, set **tx_config** and the following members of :cpp:type:`rmt_tx_config_t`: + +* Transmit the currently configured data items in a loop - **loop_en** +* Enable the RMT carrier signal - **carrier_en** +* Frequency of the carrier in Hz - **carrier_freq_hz** +* Duty cycle of the carrier signal in percent (%) - **carrier_duty_percent** +* Level of the RMT output, when the carrier is applied - **carrier_level** +* Enable the RMT output if idle - **idle_output_en** +* Set the signal level on the RMT output if idle - **idle_level** + + +Receive Mode +^^^^^^^^^^^^ + +In receive mode, set **rx_config** and the following members of :cpp:type:`rmt_rx_config_t`: + +* Enable a filter on the input of the RMT receiver - **filter_en** +* A threshold of the filter, set in the number of ticks - **filter_ticks_thresh**. Pulses shorter than this setting will be filtered out. Note, that the range of entered tick values is [0..255]. +* A pulse length threshold that will turn the RMT receiver idle, set in number of ticks - **idle_threshold**. The receiver will ignore pulses longer than this setting. + + +Finalize Configuration +^^^^^^^^^^^^^^^^^^^^^^ + +Once the :cpp:type:`rmt_config_t` structure is populated with parameters, it should be then invoked with :cpp:func:`rmt_config` to make the configuration effective. + +The last configuration step is installation of the driver in memory by calling :cpp:func:`rmt_driver_install`. If :cpp:type:`rx_buf_size` parameter of this function is > 0, then a ring buffer for incoming data will be allocated. A default ISR handler will be installed, see a note in `Use Interrupts`_. + +Now, depending on how the channel is configured, we are ready to either `Transmit Data`_ or `Receive Data`_. This is described in next two sections. + + +Transmit Data +------------- + +Before being able to transmit some RMT pulses, we need to define the pulse pattern. The minimum pattern recognized by the RMT controller, later called an 'item', is provided in a structure :cpp:type:`rmt_item32_t`, see :component_file:`soc/esp32/include/soc/rmt_struct.h`. Each 'item' consists of two pairs of two values. The first value in a pair describes the signal duration in ticks, the second provides the signal level (high or low). For example how to define and populate items see an example application :example:`peripherals/rmt_tx`. + +The items are provided to the RMT controller by calling function :cpp:func:`rmt_write_items`. This function also automatically triggers start of transmission. It may be called to wait for transmission completion or exit just after transmission start. In such case you can wait for the transmission end by calling :cpp:func:`rmt_wait_tx_done`. This function does not limit the number of data items to transmit. It is using an interrupt to successively copy the new data chunks to RMT's internal memory as previously provided data are sent out. + +Another way to provide data for transmission is by calling :cpp:func:`rmt_fill_tx_items`. In this case transmission is not started automatically. To control the transmission process use :cpp:func:`rmt_tx_start` and :cpp:func:`rmt_tx_stop`. The number of items to sent is restricted by the size of memory blocks allocated in the RMT controller's internal memory, see :cpp:func:`rmt_set_mem_block_num`. + + +Receive Data +------------ + +Before starting the receiver we need some storage for incoming items. The RMT controller has 512 x 32-bits of internal RAM shared between all eight channels. In typical scenarios it is not enough as an ultimate storage for all incoming (and outgoing) items. Therefore this API supports retrieval of incoming items on the fly to save them in a ring buffer of a size defined by the user. The size is provided when calling :cpp:func:`rmt_driver_install` discussed above. To get a handle to this buffer call :cpp:func:`rmt_get_ringbuf_handle`. + +With the above steps complete we can start the receiver by calling :cpp:func:`rmt_rx_start` and then move to checking what's inside the buffer. To do so, you can use common FreeRTOS functions that interact with the ring buffer. Please see an example how to do it in :example:`peripherals/rmt_nec_tx_rx`. + +To stop the receiver, call :cpp:func:`rmt_rx_stop`. + + +Change Operation Parameters +--------------------------- + +Previously described function :cpp:func:`rmt_config` provides a convenient way to set several configuration parameters in one shot. This is usually done on application start. Then, when the application is running, the API provides an alternate way to update individual parameters by calling dedicated functions. Each function refers to the specific RMT channel provided as the first input parameter. Most of the functions have `_get_` counterpart to read back the currently configured value. + + +Parameters Common to Transmit and Receive Mode +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* Selection of a GPIO pin number on the input or output of the RMT - :cpp:func:`rmt_set_pin` +* Number of memory blocks allocated for the incoming or outgoing data - :cpp:func:`rmt_set_mem_pd` +* Setting of the clock divider - :cpp:func:`rmt_set_clk_div` +* Selection of the clock source, note that currently one clock source is supported, the APB clock which is 80Mhz - :cpp:func:`rmt_set_source_clk` + + +Transmit Mode Parameters +^^^^^^^^^^^^^^^^^^^^^^^^ + +* Enable or disable the loop back mode for the transmitter - :cpp:func:`rmt_set_tx_loop_mode` +* Binary level on the output to apply the carrier - :cpp:func:`rmt_set_tx_carrier`, selected from :cpp:type:`rmt_carrier_level_t` +* Determines the binary level on the output when transmitter is idle - :cpp:func:`rmt_set_idle_level()`, selected from :cpp:type:`rmt_idle_level_t` + + +Receive Mode Parameters +^^^^^^^^^^^^^^^^^^^^^^^ + +* The filter setting - :cpp:func:`rmt_set_rx_filter` +* The receiver threshold setting - :cpp:func:`rmt_set_rx_idle_thresh` +* Whether the transmitter or receiver is entitled to access RMT's memory - :cpp:func:`rmt_set_memory_owner`, selection is from :cpp:type:`rmt_mem_owner_t`. + + +Use Interrupts +-------------- + +Registering of an interrupt handler for the RMT controller is done be calling :cpp:func:`rmt_isr_register`. + +.. note:: + + When calling :cpp:func:`rmt_driver_install` to use the system RMT driver, a default ISR is being installed. In such case you cannot register a generic ISR handler with :cpp:func:`rmt_isr_register`. + +The RMT controller triggers interrupts on four specific events describes below. To enable interrupts on these events, the following functions are provided: + +* RMT's receiver has finished receiving a signal - :cpp:func:`rmt_set_rx_intr_en` +* Ownership to the RMT memory block has been violated - :cpp:func:`rmt_set_err_intr_en` +* RMT's transmitter has finished transmitting the signal - :cpp:func:`rmt_set_tx_intr_en` +* The number of events the transmitter has sent matches a threshold value :cpp:func:`rmt_set_tx_thr_intr_en` + +Setting or clearing an interrupt enable mask for specific channels and events may be also done by calling :cpp:func:`rmt_set_intr_enable_mask` or :cpp:func:`rmt_clr_intr_enable_mask`. + +When servicing an interrupt within an ISR, the interrupt need to explicitly cleared. To do so, set specific bits described as ``RMT.int_clr.val.chN_event_name`` and defined as a ``volatile struct`` in :component_file:`soc/esp32/include/soc/rmt_struct.h`, where N is the RMT channel number [0, 7] and the ``event_name`` is one of four events described above. + +If you do not need an ISR anymore, you can deregister it by calling a function :cpp:func:`rmt_isr_deregister`. + + +Uninstall Driver +---------------- + +If the RMT driver has been installed with :cpp:func:`rmt_driver_install` for some specific period of time and then not required, the driver may be removed to free allocated resources by calling :cpp:func:`rmt_driver_uninstall`. + + +Application Examples +-------------------- + +* A simple RMT TX example: :example:`peripherals/rmt_tx`. +* NEC remote control TX and RX example: :example:`peripherals/rmt_nec_tx_rx`. -NEC remote control TX and RX example: :example:`peripherals/rmt_nec_tx_rx`. API Reference ------------- diff --git a/examples/peripherals/rmt_tx/Makefile b/examples/peripherals/rmt_tx/Makefile new file mode 100644 index 0000000000..f4b09f84a6 --- /dev/null +++ b/examples/peripherals/rmt_tx/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := rmt_tx + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/peripherals/rmt_tx/README.md b/examples/peripherals/rmt_tx/README.md new file mode 100644 index 0000000000..5e63859845 --- /dev/null +++ b/examples/peripherals/rmt_tx/README.md @@ -0,0 +1,25 @@ +# RMT Transmit Example + +This example shows how to configure and operate the remote control (RMT) peripheral to transmit a sample message in the [Morse code](https://en.wikipedia.org/wiki/Morse_code). + +Configuration (pin number, etc.) can be modified in the top of the `main/rmt_tx_main.c` file. + +To be able to see and hear the message output by the RMT, connect a LED and a speaker or an earphone (be careful - it may be loud) to the GPIO configured under `RMT_TX_GPIO` define (default is GPIO 18). + +Example connections: + +``` + 330R LED +GPIO18 +----/\/\/\----+------|>|-----+ GND + | + | /| + +-+ | Speaker + | | | or + +-+ | earphone + | \| + | + +--------------+ GND +``` + + +See the README.md file in the upper level 'examples' directory for more information about examples. diff --git a/examples/peripherals/rmt_tx/main/component.mk b/examples/peripherals/rmt_tx/main/component.mk new file mode 100644 index 0000000000..b4fa72791c --- /dev/null +++ b/examples/peripherals/rmt_tx/main/component.mk @@ -0,0 +1,4 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# +# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) diff --git a/examples/peripherals/rmt_tx/main/rmt_tx_main.c b/examples/peripherals/rmt_tx/main/rmt_tx_main.c new file mode 100644 index 0000000000..b19dbc2b49 --- /dev/null +++ b/examples/peripherals/rmt_tx/main/rmt_tx_main.c @@ -0,0 +1,119 @@ +/* RMT transmit example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "esp_log.h" +#include "driver/rmt.h" + +static const char *RMT_TX_TAG = "RMT Tx"; + +#define RMT_TX_CHANNEL RMT_CHANNEL_0 +#define RMT_TX_GPIO 18 +#define RMT_MESSAGE_LENGTH 12 + +rmt_item32_t items[RMT_MESSAGE_LENGTH]; + +/* + * Prepare a table with a message in the Morse code + * + * The message is "ESP" : . ... .--. + * + * The table structure: + * {duration, level, duration, level} + * + */ +uint32_t message[RMT_MESSAGE_LENGTH][4] = { + // E : dot + {32767, 1, 32767, 0}, // dot + // + {32767, 0, 32767, 0}, // SPACE + // S : dot, dot, dot + {32767, 1, 32767, 0}, // dot + {32767, 1, 32767, 0}, // dot + {32767, 1, 32767, 0}, // dot + // + {32767, 0, 32767, 0}, // SPACE + // P : dot, dash, dash, dot + {32767, 1, 32767, 0}, // dot + {32767, 1, 32767, 1}, + {32767, 1, 32767, 0}, // dash + {32767, 1, 32767, 1}, + {32767, 1, 32767, 0}, // dash + {32767, 1, 32767, 0} // dot +}; + + +/* + * Populate the RMT items array + * with a previously prepared message + */ +static void populate_rmt_items(void) +{ + for (int i = 0; i < RMT_MESSAGE_LENGTH; i++) { + items[i].duration0 = message[i][0]; + items[i].level0 = message[i][1]; + items[i].duration1 = message[i][2]; + items[i].level1 = message[i][3]; + } +} + + +/* + * Initialize the RMT Tx channel + */ +static void rmt_tx_int() +{ + rmt_config_t config; + config.rmt_mode = RMT_MODE_TX; + config.channel = RMT_TX_CHANNEL; + config.gpio_num = RMT_TX_GPIO; + config.mem_block_num = 1; + config.tx_config.loop_en = 0; + // enable the carrier to be able to hear the Morse sound + // if the RMT_TX_GPIO is connected to a speaker + config.tx_config.carrier_en = 1; + config.tx_config.idle_output_en = 1; + config.tx_config.idle_level = 0; + config.tx_config.carrier_duty_percent = 50; + // set audible career frequency of 611 Hz + // actually 611 Hz is the minimum, that can be set + // with current implementation of the RMT API + config.tx_config.carrier_freq_hz = 611; + config.tx_config.carrier_level = 1; + // set the maximum clock divider to be able to output + // RMT pulses in range of about one hundred milliseconds + config.clk_div = 255; + + ESP_ERROR_CHECK(rmt_config(&config)); + ESP_ERROR_CHECK(rmt_driver_install(config.channel, 0, 0)); +} + + +/* + * Transmit all the items in a loop + */ +static void rmt_tx_task(void *ignore) +{ + while (1) { + ESP_ERROR_CHECK(rmt_write_items(RMT_TX_CHANNEL, items, RMT_MESSAGE_LENGTH, 1)); + ESP_LOGI(RMT_TX_TAG, "Transmission complete"); + vTaskDelay(2000 / portTICK_PERIOD_MS); + } +} + + +void app_main(void *ignore) +{ + ESP_LOGI(RMT_TX_TAG, "Configuring transmitter"); + rmt_tx_int(); + populate_rmt_items(); + + ESP_LOGI(RMT_TX_TAG, "Spinning out transmit task"); + xTaskCreatePinnedToCore(&rmt_tx_task, "rmt_tx_task", 4 * 1024, NULL, 5, NULL, 0); +}