PCNT :: How to modify peripheral registers?

code4sex
Posts: 20
Joined: Tue Mar 16, 2021 12:23 pm

PCNT :: How to modify peripheral registers?

Postby code4sex » Thu Oct 05, 2023 10:56 pm

Dear Espressif,

I'm trying to set up a PCNT peripheral with a pure registry approach (non-IDF) and getting the following mind-blowing mishappening:

Code: Select all

// (1) make a snapshot of any (for example, CONF0) register prior to modification:
printf("(%08lX) = %08lX\n", (uint32_t)&PCNT.conf_unit[0].conf0, *((uint32_t*)&PCNT.conf_unit[0].conf0));

// (2) configure unit_0 as per my requirements
PCNT.conf_unit[0].conf0.filter_thres	= 0;	// This register is used to filter pulse whose width is smaller than this value for unit0.
PCNT.conf_unit[0].conf0.filter_en	= 0;	// This is the enable bit for filtering input signals for unit0.
PCNT.conf_unit[0].conf0.thr_zero_en	= 0;	// This is the enable bit for comparing unit0's count with 0 value.
PCNT.conf_unit[0].conf0.thr_h_lim_en	= 1;	// This is the enable bit for  comparing unit0's count with thr_h_lim value.
PCNT.conf_unit[0].conf0.thr_l_lim_en	= 0;	// This is the enable bit for comparing unit0's count with thr_l_lim  value.
PCNT.conf_unit[0].conf0.thr_thres0_en	= 0;	// This is the enable bit for comparing unit0's count with  thres0 value.
PCNT.conf_unit[0].conf0.thr_thres1_en	= 0;	// This is the enable bit for  comparing  unit0's count with thres1 value .
PCNT.conf_unit[0].conf0.ch0_neg_mode	= 0;	// This register is used to control the mode of channel0's input neg-edge signal for unit0. 2'd1:	increase at the negedge of input signal    2'd2:decrease at the negedge of input signal    others:forbidden
PCNT.conf_unit[0].conf0.ch0_pos_mode	= 1;	// This register is used to control the mode of channel0's input pos-edge signal for unit0. 2'd1:	increase at the posedge of input signal    2'd2:decrease at the posedge of input signal    others:forbidd
PCNT.conf_unit[0].conf0.ch0_hctrl_mode	= 0;	// This register is used to control the mode of channel0's high control signal for unit0. 2'd0:increase when control signal is low   2'd1	decrease when control signal is high   others:forbidden
PCNT.conf_unit[0].conf0.ch0_lctrl_mode	= 0;	// This register is used to control the mode of channel0's low control signal for unit0. 2'd0:increase when control signal is low   2'd1	decrease when control signal is high   others:forbidd
PCNT.conf_unit[0].conf0.ch1_neg_mode	= 0;	// This register is used to control the mode of channel1's input neg-edge signal for unit0. 2'd1пјљincrease at the negedge of input signal    2'd2:decrease at the negedge of input signal    others:forbidden
PCNT.conf_unit[0].conf0.ch1_pos_mode	= 1;	// This register is used to control the mode of channel1's input pos-edge signal for unit0. 2'd1пјљincrease at the posedge of input signal    2'd2:decrease at the posedge of input signal    others:forbidden
PCNT.conf_unit[0].conf0.ch1_hctrl_mode	= 0;	// This register is used to control the mode of channel1's high control signal for unit0. 2'd0:increase when control signal is low   2'd1пјљdecrease when control signal is high   others:forbidden
PCNT.conf_unit[0].conf0.ch1_lctrl_mode	= 0;	// This register is used to control the mode of channel1's low control signal for unit0. 2'd0:increase when control signal is low   2'd1пјљdecrease when control signal is high   others:forbidden

// (3) take another snapshot
printf("(%08lX) = %08lX\n", (uint32_t)&PCNT.conf_unit[0].conf0, *((uint32_t*)&PCNT.conf_unit[0].conf0)); 

// (4) now getthe whole thing stuck in an infinite loop:
while (PCNT.conf_unit[0].conf0.val == 0x04041000){}; // 0x04041000 here is the hex value of the just configured CONF0 register; see the printf() output below

// (5) Hell no, says esp32, there's gonna be no loop because CONF0 register has been reset to its initial value:
printf("(%08lX) = %08lX\n", (uint32_t)&PCNT.conf_unit[0].conf0, *((uint32_t*)&PCNT.conf_unit[0].conf0));
And here is the printf() output:

Code: Select all

(3FF57000) = 00003C10
(3FF57000) = 04041000
(3FF57000) = 00003C10
Once again: I can write new values, verify with printf() and after a while they are gone!
It's the only code in main(); no other tasks/functionality yet! My platorm: ESP-WROOM-32 / IDF-5.0.1

Q1: Now how am I supposed to write data to PCNT config and control registers?

PS. No matter what address base is used (0x3FF57000 or 0x60017000) it still fails...

Q2: Additionally, I don't quite understand the purpose and usage of PCNT_CLK_EN bit in the PCNT_CTRL_REG:
Can you clarify this?

"PCNT_CLK_EN Configures register clock gating.
0: Support clock only when the application writes registers. (what does it mean?)
1: Always force the clock on for registers. (what registers?)
(R/W)"

ESP_Sprite
Posts: 9709
Joined: Thu Nov 26, 2015 4:08 am

Re: PCNT :: How to modify peripheral registers?

Postby ESP_Sprite » Fri Oct 06, 2023 3:29 am

Did you enable and un-reset the peripheral? Easiest to do that using this.

code4sex
Posts: 20
Joined: Tue Mar 16, 2021 12:23 pm

Re: PCNT :: How to modify peripheral registers?

Postby code4sex » Fri Oct 06, 2023 9:55 am

ESP_Sprite, wow! Thank you for a timely reply! Highly appreciate.

(1) Yes, it was my mistake for omitting the prior call to enable and un-reset the peripheral.
I do confirm that after adding either blocks of code PCNT starts off:

Code: Select all

periph_module_enable(PERIPH_PCNT_MODULE);
or

Code: Select all

#include "soc/dport_access.h"
#include "soc/dport_reg.h"
DPORT_REG_SET_BIT(DPORT_PERIP_CLK_EN_REG, DPORT_PCNT_CLK_EN);
DPORT_REG_CLR_BIT(DPORT_PERIP_RST_EN_REG, DPORT_PCNT_RST);
Thanks for reminding.

PS. I'm sure users would appreciate if you added such a "boilerpate" in the beginning of each peripheral section in the TRM... TRM is big and heavy and you can easily forget some important details from it in the distant sections...

(2) Additionaly, can you please explain what PCNT_CLK_EN bit in the PCNT_CTRL_REG actually does.... ?
I don't observe any difference in the PCNT behaviour when I try both values:

Code: Select all

PCNT.ctrl.clk_en = 0;
PCNT.ctrl.clk_en = 1;
Does it have smth to do with deep internals?

ESP_Sprite
Posts: 9709
Joined: Thu Nov 26, 2015 4:08 am

Re: PCNT :: How to modify peripheral registers?

Postby ESP_Sprite » Sat Oct 07, 2023 8:36 am

code4sex wrote:
Fri Oct 06, 2023 9:55 am
PS. I'm sure users would appreciate if you added such a "boilerpate" in the beginning of each peripheral section in the TRM... TRM is big and heavy and you can easily forget some important details from it in the distant sections...
Yes, we have an outstanding issue for this.
(2) Additionaly, can you please explain what PCNT_CLK_EN bit in the PCNT_CTRL_REG actually does.... ?
I don't observe any difference in the PCNT behaviour when I try both values:

Code: Select all

PCNT.ctrl.clk_en = 0;
PCNT.ctrl.clk_en = 1;
Does it have smth to do with deep internals?

Kind of. The way I understand it, the hardware tries to be smart, clockgating bits of the peripheral when it's not needed. This bit can override that, in case we made a boo-boo and something actually does need that clock while the logic would like to switch it off.
Generally, you shouldn't have to touch that bit.

Who is online

Users browsing this forum: MicroController and 92 guests