How to configure and enable pwm1 in Hifive1 Rev B

Hi,

I try to trigger pwm1 and capture the waveform on scope.

Here are my changes.

Set Gpio1 as IO function pin in gpio iof register.
0x10012038: 0x00000002

Select PWM function for gpio1 in iof select register.
0x1001203c: 0x00000002

Configure pwmcfg regiter (scale 3, enabled both pwm0 and pwm1center, disabled gang)
0x10015000: 0x000f1003

Set pwmcmp0 register to ff.
0x10015020: 0x000000ff

But I dont see any change in the gpio1 pin state. What am I missing?
Any help is appreciated.

1 Like

Hi @bsvtgc nice to see you again.

PWM doesn’t like its counter or comparator being changed when it is running. The following sequence of separate steps work well for me.

You usually want to use cmp0 to set the periodicity, since it’s at the bottom (least-significant or most repetitious) end of the chain, and use cmp1 to work the duty cycle. You can simultaneously use cmp2 and cmp3 as well, each for different duty cycles if you wish. Of course, you must both enable and select the IOFs of GPIO2 and GPIO3 in that case, as you do above for GPIO1.

pwm0_cfg  = 0;
pwm0_count = 0;
pwm0_scount = 0;
pwm0_cmp0 = (1000) - 1;            // for dividing by 1000
pwm0_cmp1 = (pwm1_cmp0 + 1) >> 1;  // for 50 percent duty
pwm0_cfg |= (PWM_CFG_ENALWAYS | PWM_CFG_DEGLITCH | PWM_CFG_ZEROCMP | 0); // scale 0..15

This should give you an external monitor signal on GPIO1 (the 48-QFN pin 26) for the internal clock … divided by 1000x. It nicely resolves MHz to KHz for an inexpensive scope.

#define pwm0_base 0x10015000
#define pwm1_base 0x10025000
#define pwm2_base 0x10035000

#define pwm0_cfg    (*(volatile uint32_t *) (pwm0_base + 0x00))
#define pwm0_count  (*(volatile uint32_t *) (pwm0_base + 0x08))
#define pwm0_scount (*(volatile uint32_t *) (pwm0_base + 0x10))
#define pwm0_cmp0   (*(volatile uint32_t *) (pwm0_base + 0x20))
#define pwm0_cmp1   (*(volatile uint32_t *) (pwm0_base + 0x24))
#define pwm0_cmp2   (*(volatile uint32_t *) (pwm0_base + 0x28))
#define pwm0_cmp3   (*(volatile uint32_t *) (pwm0_base + 0x2C))

#define pwm1_cfg    (*(volatile uint32_t *) (pwm1_base + 0x00))
#define pwm1_count  (*(volatile uint32_t *) (pwm1_base + 0x08))
#define pwm1_scount (*(volatile uint32_t *) (pwm1_base + 0x10))
#define pwm1_cmp0   (*(volatile uint32_t *) (pwm1_base + 0x20))
#define pwm1_cmp1   (*(volatile uint32_t *) (pwm1_base + 0x24))
#define pwm1_cmp2   (*(volatile uint32_t *) (pwm1_base + 0x28))
#define pwm1_cmp3   (*(volatile uint32_t *) (pwm1_base + 0x2C))

#define pwm2_cfg    (*(volatile uint32_t *) (pwm2_base + 0x00))
#define pwm2_count  (*(volatile uint32_t *) (pwm2_base + 0x08))
#define pwm2_scount (*(volatile uint32_t *) (pwm2_base + 0x10))
#define pwm2_cmp0   (*(volatile uint32_t *) (pwm2_base + 0x20))
#define pwm2_cmp1   (*(volatile uint32_t *) (pwm2_base + 0x24))
#define pwm2_cmp2   (*(volatile uint32_t *) (pwm2_base + 0x28))
#define pwm2_cmp3   (*(volatile uint32_t *) (pwm2_base + 0x2C))

#define PWM_CFG_CMP3IP    0x80000000  // [31]
#define PWM_CFG_CMP2IP    0x40000000  // [30]
#define PWM_CFG_CMP1IP    0x20000000  // [29]
#define PWM_CFG_CMP0IP    0x10000000  // [28]
#define PWM_CFG_CMP3GANG  0x08000000  // [27]
#define PWM_CFG_CMP2GANG  0x04000000  // [26]
#define PWM_CFG_CMP1GANG  0x02000000  // [25]
#define PWM_CFG_CMP0GANG  0x01000000  // [24]

#define PWM_CFG_CMP3CTR   0x00080000  // [19]
#define PWM_CFG_CMP2CTR   0x00040000  // [18]
#define PWM_CFG_CMP1CTR   0x00020000  // [17]
#define PWM_CFG_CMP0CTR   0x00010000  // [16]

#define PWM_CFG_ENONESHOT 0x00002000  // [13]
#define PWM_CFG_ENALWAYS  0x00001000  // [12]

#define PWM_CFG_DEGLITCH  0x00000400  // [10]
#define PWM_CFG_ZEROCMP   0x00000200  // [9]
#define PWM_CFG_STICKY    0x00000100  // [8]
#define PWM_CFG_SCALE     0x0000000F  // [3:0]

Hello @pds good to hear from you :slight_smile: . How are you? Hope this finds you well.

Here is the thing I am working on.

I try to set the tlclk/core clk to operate at 200 Mhz. After calculating the values for VCO, here is what I find & write. The red lines are your picture while ago for reset values. Green text are my settings/configurations.

Confirmed the same thru gdb dump of clk cfg register.

(gdb) x /x 0x10008008
0x10008008:	0x80030981
(gdb)

The MSbit is set confirmed the pll is ready and running.

with above clock settings, want to confirm if the clock is really running at 200MHz. Hence configured pwm0 and scoped it.

// pmpcmp0 value to 999
/* set compare value to adjust duty cycle on pwmx_0 */
            let pwmcmp0: *mut u32 = PWM_INSTANCE0_BASE_ADDR.byte_add(0x20);
            write_volatile(pwmcmp0, 999); // only lower 16 bits writable

I was expecting 200Khz, instead its ~ 430 Khz.

Let me know if you find anything wrong above.

To answer to your comment on PWM dont like changing values after enabled. In code I dont do that. Its all configured, then enabled as below. Its embedded rust code.

let cfg_ptr = PWM_INSTANCE0_BASE_ADDR;
            write_volatile(cfg_ptr, read_volatile(cfg_ptr) | ( 0x1 << 12 as u32));

Once your response confirmed nothing wrong on my code in pwm, digged into find out that I was probing the wrong pin on board (silk number 9 instead of 8).

1 Like