Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 4790

Bare metal, Assembly language • PWM serialiser mode on RPI5

$
0
0
Hello,

I wrote a routine to send an SDLC frame (NRZI) via PWM in serialised mode to replace TX of a Zilog ESCC (with GPIO cycles) originally on the CM4 and now on the RPI5 (RP1). This mode is also used for the WS2812.
DMA here is not used, FIFO is quite large (16 x 32 bits on the BCM2711).

I had a few issues with the RP1:
1> To see if everything is sent, you need to test the number of characters in the FIFO, the Empty bit comes way too early.
2> Does clearing FIFO sometimes have the opposite effect, or I maybe have to wait for the result? (I removed the sequence)
3> Instead of putting 32 bits in range, I have to put 31!

Otherwise it works, Here are the sources:

Code:

#include <string.h>#include <stdint.h>#include "FreeRTOS.h"#include "BCM2835/lib/synchronize.h"#include "BCM2835/drivers/rpi_pwm.h"#include "BCM2835/drivers/rpi_pwm_rp1.h"#include "BCM2835/drivers/rpi_gpio.h"#include "BCM2835/drivers/rpi_gpio_clk.h"#include "BCM2835/drivers/rpi_clk_rp1.h"#include "BCM2835/drivers/rpi_systimer.h"#define GPIO_TX 18 // PWMtypedef struct {  union {    struct {      uint16_t duration :15;      uint16_t level :1;    };    uint16_t val;  };} rmt_item16_t;#define SYNC 0x55#define FLAG 0x7E#define NUM_PREAMBLE 1#define NUM_POSTAMBLE 1#define MAX_SIZE 64#define DEFAULT_BITRATE 375000static uint32_t bitrate = 0;static rmt_item16_t item_buf[MAX_SIZE * 8];static unsigned char tmp_buf[MAX_SIZE + 2];static uint32_t out_buf[MAX_SIZE + 1];/* calculate time of pulse */static inline void make_pulse(rmt_item16_t *item16, int du, int lv){  item16->duration = du;  item16->level = lv;}/* make pulses from data byte */static int byte_to_pulse(rmt_item16_t *item16, int item16_size, uint8_t data, int *dup, int *lvp, int bsflag){  int i = 0; // index of item16[]  uint8_t b;  int du = *dup;  int lv = *lvp;  for(b = 1; b != 0; b <<= 1)  { // scan data byte, LSb first    if(b & data)    { // check data bit      // send 1      du++;      if(bsflag && (du >= 6))      { // insert 0 (bit stuffing)        if(i >= item16_size)          break;        make_pulse(&item16[i++], du, lv);        du = 1; // bit stuffing 0        lv = !lv;      }    }    else    {      // send 0      if(i >= item16_size)        break;      make_pulse(&item16[i++], du, lv); // make '1' pulse      du = 1; // next '0' pulse duration      lv = !lv; // invert level    }  }  *dup = du;  *lvp = lv;  return i; // number of item16}/* * make NRZI pulses from packet data */static int make_nrzi_pulses(rmt_item16_t *item16, int item16_size, unsigned char data[], int data_len){  int i;  int du = 1; // duration, always start 0 data bit  int lv = 1; // level, idle level is 1  int idx = 0; // index of item16[] to be stored next pulse  /* preamble, bit stuffing off */  for(i = 0; i < NUM_PREAMBLE; i++)    idx += byte_to_pulse(&item16[idx], item16_size - idx, FLAG, &du, &lv, 0); // no bit stuffing  /* packet data, bit stuffing on */  for(i = 0; i < data_len; i++) /* char data */    idx += byte_to_pulse(&item16[idx], item16_size - idx, data[i], &du, &lv, 1); // insert bit stuffing  /* postamble, bit stuffing off */  for(i = 0; i < NUM_POSTAMBLE; i++)    idx += byte_to_pulse(&item16[idx], item16_size - idx, FLAG, &du, &lv, 0); // no bit stuffing  // end mark  if(idx < item16_size)  {    item16[idx].duration = 0; // 0 means end of pulses    item16[idx].level = 0;    idx++;  }  return idx; // return value is number of item}#define INITFCS 0xFFFF#define GOODFCS 0xF0B8static unsigned short fcstab[256] = {   /* 00 */ 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,   /* 08 */ 0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,   /* 10 */ 0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,   /* 18 */ 0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,   /* 20 */ 0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,   /* 28 */ 0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,   /* 30 */ 0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,   /* 38 */ 0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,   /* 40 */ 0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,   /* 48 */ 0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,   /* 50 */ 0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,   /* 58 */ 0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,   /* 60 */ 0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,   /* 68 */ 0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,   /* 70 */ 0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,   /* 78 */ 0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,   /* 80 */ 0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,   /* 88 */ 0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,   /* 90 */ 0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,   /* 98 */ 0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,   /* a0 */ 0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,   /* a8 */ 0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,   /* b0 */ 0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,   /* b8 */ 0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,   /* c0 */ 0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,   /* c8 */ 0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,   /* d0 */ 0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,   /* d8 */ 0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,   /* e0 */ 0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,   /* e8 */ 0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,   /* f0 */ 0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,   /* f8 */ 0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78};/* *  HDLC FCS computation. Read RFC 1171 Appendix B and CCITT X.25 section *  2.27 for further details. */static unsigned short sdlc_build_crc(unsigned char *buffer, int size){  unsigned short fcs = INITFCS;  while(size--)    fcs = (fcs >> 8) ^ fcstab[(fcs ^ *buffer++) & 0xff];  return(~fcs);}void sdlc_init(uint32_t baud){  unsigned ref = rpi_gpio_get_clk_rate(GPIOClockSourcePLLD);  unsigned divi = ref / baud;  unsigned divf = (unsigned)((((double)ref / (double)baud) - (double)divi) * 4096.);  if(rpi_type < 5)  {    rpi_gpio_clk_stop(GPIOClockPWM);    rpi_gpio_clk_start(GPIOClockPWM, GPIOClockSourcePLLD, divi, divf, divf ? 1 : 0);    rpi_gpio_sel_fun(GPIO_TX, RPI_GPIO_FSEL_ALT5);  }#ifdef AARCH64  else  {    rpi_clk_rp1_start_rate(RPI_RP1_CLK_PWM0, baud);    rpi_gpio_sel_fun(GPIO_TX, RPI_GPIO_FSEL_ALT3); /* PWM0 channel 2 */  }#endif /* AARCH64 */  bitrate = baud;}int sdlc_send_frame(unsigned char *buffer, int buffer_size){  uint32_t len = 0, start = 0;  int i, j, n, bit, nb = 0, current_ipl;  unsigned short fcs;  if((buffer == NULL) || (buffer_size >= MAX_SIZE))    return(-1);  memcpy(tmp_buf, buffer, buffer_size);  memset(out_buf, 0, sizeof(out_buf));  fcs = sdlc_build_crc(buffer, buffer_size);  tmp_buf[buffer_size] = (unsigned char)fcs;  tmp_buf[buffer_size + 1] = (unsigned char)(fcs >> 8);  n = make_nrzi_pulses(item_buf, sizeof(item_buf) / sizeof(rmt_item16_t), tmp_buf, buffer_size + 2);  len += 3;  len >>= 2; // 32 bits alignment  bit = 15; // MSB first - 2 x SYNC  out_buf[len] = (SYNC << 24) | (SYNC << 16);  for(i = 0; i < n; i++)  {    if(!item_buf[i].duration && i)    {      if(item_buf[i-1].level)        out_buf[len] |= (1 << bit);      else        out_buf[len] &= ~(1 << bit);      len++;      break;    }    for(j = 0; j < (int)item_buf[i].duration; j++)    {      if(!item_buf[i].level)        out_buf[len] |= (1 << bit); // polarity inverted      else        out_buf[len] &= ~(1 << bit);      bit--;      if(bit < 0)      {        bit = 31;        len++;        if(len >= (sizeof(out_buf) / sizeof(uint32_t)))          return(-1);      }      nb++;    }  }  len++; // Last data in FIFO  if(!bitrate)    sdlc_init(DEFAULT_BITRATE);  current_ipl = vPortSetIPL(portIPL_MAX);  dmb();  if(rpi_type < 5)  {    // Clear PWM control & status register    RPI_PWM->CTL = 0;    // Set transmission range (32 bits)    RPI_PWM->RNG1 = 32;    // Enable serializer mode / Clear the FIFO / Use FIFO rather than DAT1    RPI_PWM->CTL = RPI_PWM_CTL_MODE1 | RPI_PWM_CTL_POLA1 | RPI_PWM_CTL_USEF1 | RPI_PWM_CTL_CLRF1; /* Serialiser mode, Repeat Last Data, Polarity, Use FIFO, Clear FIFO */    // Enable PWM    RPI_PWM->CTL |= RPI_PWM_CTL_PWEN1;    // Fill the FIFO    for(i = 0; i < len; RPI_PWM->FIF1 = out_buf[i++]);  }#ifdef AARCH64  else if(rp1_ok)  {    // Set transmission range (32 bits)    RPI_PWM0_RP1->COMMON_RANGE = 31;    // MSB serialiser output    RPI_PWM0_RP1->CHAN2_CTRL = RPI_PWM_RP1_CHAN_CTRL_FIFO_POP | RPI_PWM_RP1_CHAN_CTRL_USEFIFO | RPI_PWM_RP1_CHAN_CTRL_BIND | RPI_PWM_RP1_CHAN_CTRL_INVERT | (4 << RPI_PWM_RP1_CHAN_CTRL_MODE_SHIFT);    // Enable PWM    RPI_PWM0_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_CHAN2_EN;    RPI_PWM0_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_SET_UPDATE;    // Fill the FIFO    for(i = 0; i < len; RPI_PWM0_RP1->DUTY_FIFO = out_buf[i++]);  }#endif /* AARCH64 */  vPortSetIPL(current_ipl);  return(0);}int sdlc_send_frame_ok(void){#ifdef AARCH64  if(rpi_type >= 5)  {    if(rp1_ok)      return((((RPI_PWM0_RP1->FIFO_CTRL & RPI_PWM_RP1_FIFO_CTRL_LEVEL_MASK) >> RPI_PWM_RP1_FIFO_CTRL_LEVEL_SHIFT) == 0) ? 1 : 0 );    return(0);  }#endif  return((RPI_PWM->STA & RPI_PWM_STA_EMPT1) ? 1 : 0 );}

Code:

#ifndef _RPI_PWM_RP1_H_#define _RPI_PWM_RP1_H_#include "rpi_base.h"#define RPI_PWM0_RP1_BASE                 (uintptr_t)(MEM_PCIE_RANGE_START + 0x98000)#define RPI_PWM1_RP1_BASE                 (uintptr_t)(MEM_PCIE_RANGE_START + 0x9C000)//// PWM fifo control register//#define RPI_PWM_RP1_FIFO_CTRL_LEVEL_SHIFT0#define RPI_PWM_RP1_FIFO_CTRL_LEVEL_MASK(0x1F << 0)#define RPI_PWM_RP1_FIFO_CTRL_FLUSH(1 << 5)#define RPI_PWM_RP1_FIFO_CTRL_FLUSH_DONE(1 << 6)#define RPI_PWM_RP1_FIFO_CTRL_THRESHOLD_SHIFT11#define RPI_PWM_RP1_FIFO_CTRL_THRESHOLD_MASK(0x1F << 11)#define RPI_PWM_RP1_FIFO_CTRL_DWELL_TIME_SHIFT16#define RPI_PWM_RP1_FIFO_CTRL_DWELL_TIME_MASK(0x1F << 16)#define RPI_PWM_RP1_FIFO_CTRL_DREQ_EN(1 << 31)//// PWM global control register//#define RPI_PWM_RP1_GLOBAL_CTRL_CHAN0_EN(1 << 0)#define RPI_PWM_RP1_GLOBAL_CTRL_CHAN1_EN(1 << 1)#define RPI_PWM_RP1_GLOBAL_CTRL_CHAN2_EN(1 << 2)#define RPI_PWM_RP1_GLOBAL_CTRL_CHAN3_EN(1 << 3)#define RPI_PWM_RP1_GLOBAL_CTRL_SET_UPDATE(1 << 31)//// PWM channel control register//#define RPI_PWM_RP1_CHAN_CTRL_MODE_SHIFT0#define RPI_PWM_RP1_CHAN_CTRL_MODE_MASK(7 << 0)#define RPI_PWM_RP1_CHAN_CTRL_INVERT(1 << 3)#define RPI_PWM_RP1_CHAN_CTRL_BIND(1 << 4)#define RPI_PWM_RP1_CHAN_CTRL_USEFIFO(1 << 5)#define RPI_PWM_RP1_CHAN_CTRL_SDM(1 << 6)#define RPI_PWM_RP1_CHAN_CTRL_DITHER(1 << 7)#define RPI_PWM_RP1_CHAN_CTRL_FIFO_POP(1 << 8)#define RPI_PWM_RP1_CHAN_CTRL_SDM_BITWIDTH_SHIFT12#define RPI_PWM_RP1_CHAN_CTRL_SDM_BITWIDTH(15 << 12)#define RPI_PWM_RP1_CHAN_CTRL_SDM_BIAS_SHIFT16#define RPI_PWM_RP1_CHAN_CTRL_SDM_BIAS_MASK     (0xFFFF < 16)//// PWM interrupt raw//#define RPI_PWM_RP1_INTR_FIFO_UNDERFLOW(1 << 0)#define RPI_PWM_RP1_INTR_FIFO_OVERFLOW(1 << 1)#define RPI_PWM_RP1_INTR_FIFO_EMPTY(1 << 2)#define RPI_PWM_RP1_INTR_FIFO_FULL(1 << 3)#define RPI_PWM_RP1_INTR_DREQ_ACTIVE(1 << 4)#define RPI_PWM_RP1_INTR_CHAN0_RELOAD(1 << 5)#define RPI_PWM_RP1_INTR_CHAN1_RELOAD(1 << 6)#define RPI_PWM_RP1_INTR_CHAN2_RELOAD(1 << 7)#define RPI_PWM_RP1_INTR_CHAN3_RELOAD(1 << 8)typedef struct {  volatile uint32_t GLOBAL_CTRL;///< 0x00 Global control bits  volatile uint32_t FIFO_CTRL;///< 0x04 FIFO thresholding and status  volatile uint32_t COMMON_RANGE;///< 0x08  volatile uint32_t COMMON_DUTY;///< 0x0c  volatile uint32_t DUTY_FIFO;///< 0x10  volatile uint32_t CHAN0_CTRL;///< 0x14  Channel 0 control register  volatile uint32_t CHAN0_RANGE;///< 0x18  volatile uint32_t CHAN0_PHASE;///< 0x1c  volatile uint32_t CHAN0_DUTY;///< 0x20  volatile uint32_t CHAN1_CTRL;///< 0x24  Channel 1 control register  volatile uint32_t CHAN1_RANGE;///< 0x28  volatile uint32_t CHAN1_PHASE;///< 0x2c  volatile uint32_t CHAN1_DUTY;///< 0x30  volatile uint32_t CHAN2_CTRL;///< 0x34  Channel 2 control register  volatile uint32_t CHAN2_RANGE;///< 0x38  volatile uint32_t CHAN2_PHASE;///< 0x3c  volatile uint32_t CHAN2_DUTY;///< 0x40  volatile uint32_t CHAN3_CTRL ;///< 0x44 Channel 3 control register  volatile uint32_t CHAN3_RANGE;///< 0x48  volatile uint32_t CHAN3_PHASE;///< 0x4c  volatile uint32_t CHAN3_DUTY;///< 0x50  volatile uint32_t INTR;///< 0x54  Raw Interrupts  volatile uint32_t INTE;///< 0x58  Interrupt Enable  volatile uint32_t INTF;///< 0x5c  Interrupt Force  volatile uint32_t INTS;///< 0x60  Interrupt status after masking & forcing} RPI_PWM_RP1_t;#define RPI_PWM0_RP1((RPI_PWM_RP1_t *)  RPI_PWM0_RP1_BASE)#define RPI_PWM1_RP1((RPI_PWM_RP1_t *)  RPI_PWM1_RP1_BASE)extern long VirtualSwitch;static inline void rpi_pwm0_rp1(int ch, uint32_t period, uint32_t duty_cycle, int polarity, int enable){  uint32_t ctrl = RPI_PWM_RP1_CHAN_CTRL_FIFO_POP | (1 << RPI_PWM_RP1_CHAN_CTRL_MODE_SHIFT);  if(polarity)    ctrl |= RPI_PWM_RP1_CHAN_CTRL_INVERT;  switch(ch)  {    case 0:      RPI_PWM0_RP1->CHAN0_RANGE = period;      RPI_PWM0_RP1->CHAN0_DUTY = duty_cycle;      RPI_PWM0_RP1->CHAN0_CTRL = ctrl;      if(enable)        RPI_PWM0_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_CHAN0_EN;      else        RPI_PWM0_RP1->GLOBAL_CTRL &= ~RPI_PWM_RP1_GLOBAL_CTRL_CHAN0_EN;      break;    case 1:      RPI_PWM0_RP1->CHAN1_RANGE = period;      RPI_PWM0_RP1->CHAN1_DUTY = duty_cycle;      RPI_PWM0_RP1->CHAN1_CTRL = ctrl;      if(enable)        RPI_PWM0_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_CHAN1_EN;      else        RPI_PWM0_RP1->GLOBAL_CTRL &= ~RPI_PWM_RP1_GLOBAL_CTRL_CHAN1_EN;      break;    case 2:      RPI_PWM0_RP1->CHAN2_RANGE = period;      RPI_PWM0_RP1->CHAN2_DUTY = duty_cycle;      RPI_PWM0_RP1->CHAN2_CTRL = ctrl;      if(enable)        RPI_PWM0_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_CHAN2_EN;      else        RPI_PWM0_RP1->GLOBAL_CTRL &= ~RPI_PWM_RP1_GLOBAL_CTRL_CHAN2_EN;      break;    case 3:      RPI_PWM0_RP1->CHAN3_RANGE = period;      RPI_PWM0_RP1->CHAN3_DUTY = duty_cycle;      RPI_PWM0_RP1->CHAN3_CTRL = ctrl;      if(enable)        RPI_PWM0_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_CHAN3_EN;      else        RPI_PWM0_RP1->GLOBAL_CTRL &= ~RPI_PWM_RP1_GLOBAL_CTRL_CHAN3_EN;      break;  }  RPI_PWM0_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_SET_UPDATE;}static inline void rpi_pwm1_rp1(int ch, uint32_t period, uint32_t duty_cycle, int polarity, int enable){  uint32_t ctrl = RPI_PWM_RP1_CHAN_CTRL_FIFO_POP | (1 << RPI_PWM_RP1_CHAN_CTRL_MODE_SHIFT);  if(polarity)    ctrl |= RPI_PWM_RP1_CHAN_CTRL_INVERT;  switch(ch)  {    case 0:      RPI_PWM1_RP1->CHAN0_RANGE = period;      RPI_PWM1_RP1->CHAN0_DUTY = duty_cycle;      RPI_PWM1_RP1->CHAN0_CTRL = ctrl;      if(enable)        RPI_PWM1_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_CHAN0_EN;      else        RPI_PWM1_RP1->GLOBAL_CTRL &= ~RPI_PWM_RP1_GLOBAL_CTRL_CHAN0_EN;      break;    case 1:      RPI_PWM1_RP1->CHAN1_RANGE = period;      RPI_PWM1_RP1->CHAN1_DUTY = duty_cycle;      RPI_PWM1_RP1->CHAN1_CTRL = ctrl;      if(enable)        RPI_PWM1_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_CHAN1_EN;      else        RPI_PWM1_RP1->GLOBAL_CTRL &= ~RPI_PWM_RP1_GLOBAL_CTRL_CHAN1_EN;      break;    case 2:      RPI_PWM1_RP1->CHAN2_RANGE = period;      RPI_PWM1_RP1->CHAN2_DUTY = duty_cycle;      RPI_PWM1_RP1->CHAN2_CTRL = ctrl;      if(enable)        RPI_PWM1_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_CHAN2_EN;      else        RPI_PWM1_RP1->GLOBAL_CTRL &= ~RPI_PWM_RP1_GLOBAL_CTRL_CHAN2_EN;      break;    case 3:      RPI_PWM1_RP1->CHAN3_RANGE = period;      RPI_PWM1_RP1->CHAN3_DUTY = duty_cycle;      RPI_PWM1_RP1->CHAN3_CTRL = ctrl;      if(enable)        RPI_PWM1_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_CHAN3_EN;      else        RPI_PWM1_RP1->GLOBAL_CTRL &= ~RPI_PWM_RP1_GLOBAL_CTRL_CHAN3_EN;      break;  }  RPI_PWM1_RP1->GLOBAL_CTRL |= RPI_PWM_RP1_GLOBAL_CTRL_SET_UPDATE;}#endif /* _RPI_PWM_RP1_H_ */

Statistics: Posted by aniplay — Sat Mar 09, 2024 12:58 pm — Replies 0 — Views 18



Viewing all articles
Browse latest Browse all 4790

Trending Articles