Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
PwmOut.cpp
00001 #include "mbed.h" 00002 #include "math.h" 00003 00004 extern volatile uint32_t *bcm2835_pwm; 00005 extern volatile uint32_t *bcm2835_clk; 00006 00007 /******************************************************************** 00008 * 00009 * PwmOut 00010 * 00011 ********************************************************************/ 00012 /** Create a PwmOut connected to the specified pin 00013 * 00014 * @param pin PwmOut pin to connect to 00015 */ 00016 PwmOut::PwmOut(PinName pin) : 00017 _pwmPin(pin), 00018 _duty_cycle(0) 00019 { 00020 // Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there 00021 bcm2835_gpio_fsel(_pwmPin, BCM2835_GPIO_FSEL_ALT5); 00022 // Set default PWM period to 20ms (usually used by servos) 00023 period_ms(20); 00024 } 00025 00026 /** 00027 * @brief 00028 * @note 00029 * @param 00030 * @retval 00031 */ 00032 PwmOut::~PwmOut() 00033 { 00034 bcm2835_gpio_fsel(_pwmPin, BCM2835_GPIO_FSEL_INPT); 00035 } 00036 00037 /** Set the output duty-cycle, specified as a percentage (float) 00038 * 00039 * @param value A floating-point value representing the output duty-cycle, 00040 * specified as a percentage. The value should lie between 00041 * 0.0f (representing on 0%) and 1.0f (representing on 100%). 00042 * Values outside this range will be saturated to 0.0f or 1.0f. 00043 */ 00044 void PwmOut::write(float value) 00045 { 00046 _duty_cycle = value; 00047 00048 if (value < 0) { 00049 _duty_cycle = 0; 00050 } 00051 00052 if (value > 1.0) { 00053 _duty_cycle = 1.0; 00054 } 00055 00056 bcm2835_pwm_set_data(PWM_CHANNEL, _duty_cycle * _range); 00057 bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1); // channel, MARKSPACE mode, active 00058 } 00059 00060 /** Return the current output duty-cycle setting, measured as a percentage (float) 00061 * 00062 * @returns 00063 * A floating-point value representing the current duty-cycle being output on the pin, 00064 * measured as a percentage. The returned value will lie between 00065 * 0.0f (representing on 0%) and 1.0f (representing on 100%). 00066 * 00067 * @note 00068 * This value may not match exactly the value set by a previous write(). 00069 */ 00070 float PwmOut::read() 00071 { 00072 return _duty_cycle; 00073 } 00074 00075 /** Set the PWM period, specified in bcm2835PWMPulseWidth (micro/nano seconds), keeping the duty cycle the same. 00076 * @note Sets clock divider according to the required period. 00077 * @param period Change the period of a PWM signal. The allowed values are: 00078 * BCM2835_PWM_PERIOD_833_NS -> 833.33 ns = 1200.000 kHz 00079 */ 00080 void PwmOut::period_ms(int period_ms) 00081 { 00082 _range = period_ms * 1200; 00083 bcm2835_pwm_set_clock(BCM2835_PWM_PERIOD_833_NS); // clock pulse = 833.33 ns 00084 bcm2835_pwm_set_range(PWM_CHANNEL, _range); 00085 } 00086 00087 /** Set the PWM period, specified in bcm2835PWMPulseWidth (micro/nano seconds), keeping the duty cycle the same. 00088 * @note Sets clock divider according to the required period. 00089 * @param period Change the period of a PWM signal. The allowed values are: 00090 * BCM2835_PWM_PERIOD_104_NS -> 104.16 ns = 9600.000 kHz 00091 */ 00092 void PwmOut::period_us(int period_us) 00093 { 00094 _range = rintf(period_us * 9.600f); 00095 bcm2835_pwm_set_clock(BCM2835_PWM_PERIOD_104_NS); 00096 bcm2835_pwm_set_range(PWM_CHANNEL, _range); 00097 } 00098 00099 /*********************************************************************** 00100 * 00101 * PWM 00102 * 00103 ***********************************************************************/ 00104 00105 /*! Sets the PWM clock divisor, 00106 to control the basic PWM pulse widths. 00107 \param[in] divisor Divides the basic 19.2MHz PWM clock. You can use one of the common 00108 values BCM2835_PWM_CLOCK_DIVIDER_* in \ref bcm2835PWMClockDivider 00109 */ 00110 void bcm2835_pwm_set_clock(uint32_t divisor) 00111 { 00112 if (bcm2835_clk == MAP_FAILED || bcm2835_pwm == MAP_FAILED) { 00113 return; /* bcm2835_init() failed or not root */ 00114 } 00115 00116 /* From Gerts code */ 00117 divisor &= 0xfff; 00118 00119 /* Stop PWM clock */ 00120 bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x01); 00121 bcm2835_delay(110); /* Prevents clock going slow */ 00122 00123 /* Wait for the clock to be not busy */ 00124 while ((bcm2835_peri_read(bcm2835_clk + BCM2835_PWMCLK_CNTL) & 0x80) != 0) 00125 bcm2835_delay(1); 00126 00127 /* set the clock divider and enable PWM clock */ 00128 bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_DIV, BCM2835_PWM_PASSWRD | (divisor << 12)); 00129 bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x11); /* Source=osc and enable */ 00130 } 00131 00132 /*! Sets the mode of the given PWM channel, 00133 allowing you to control the PWM mode and enable/disable that channel 00134 \param[in] channel The PWM channel. 0 or 1. 00135 \param[in] markspace Set true if you want Mark-Space mode. 0 for Balanced mode. 00136 \param[in] enabled Set true to enable this channel and produce PWM pulses. 00137 */ 00138 void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled) 00139 { 00140 if (bcm2835_clk == MAP_FAILED || bcm2835_pwm == MAP_FAILED) { 00141 return; /* bcm2835_init() failed or not root */ 00142 } 00143 00144 /* If you use the barrier here, wierd things happen, and the commands dont work */ 00145 00146 /* 00147 uint32_t control = bcm2835_peri_read(bcm2835_pwm + BCM2835_PWM_CONTROL); 00148 00149 if (channel == 0) { 00150 if (markspace) 00151 control |= BCM2835_PWM0_MS_MODE; 00152 else 00153 control &= ~BCM2835_PWM0_MS_MODE; 00154 if (enabled) 00155 control |= BCM2835_PWM0_ENABLE; 00156 else 00157 control &= ~BCM2835_PWM0_ENABLE; 00158 } 00159 else 00160 if (channel == 1) { 00161 if (markspace) 00162 control |= BCM2835_PWM1_MS_MODE; 00163 else 00164 control &= ~BCM2835_PWM1_MS_MODE; 00165 if (enabled) 00166 control |= BCM2835_PWM1_ENABLE; 00167 else 00168 control &= ~BCM2835_PWM1_ENABLE; 00169 } 00170 00171 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, control); 00172 */ 00173 00174 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, BCM2835_PWM0_ENABLE | BCM2835_PWM1_ENABLE | BCM2835_PWM0_MS_MODE | BCM2835_PWM1_MS_MODE); 00175 } 00176 00177 /*! Sets the maximum range of the PWM output. 00178 The data value can vary between 0 and this range to control PWM output 00179 \param[in] channel The PWM channel. 0 or 1. 00180 \param[in] range The maximum value permitted for DATA. 00181 */ 00182 void bcm2835_pwm_set_range(uint8_t channel, uint32_t range) 00183 { 00184 if (bcm2835_clk == MAP_FAILED || bcm2835_pwm == MAP_FAILED) 00185 return; /* bcm2835_init() failed or not root */ 00186 00187 if (channel == 0) 00188 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_RANGE, range); 00189 else 00190 if (channel == 1) 00191 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_RANGE, range); 00192 } 00193 00194 /*! Sets the PWM pulse ratio to emit to DATA/RANGE, 00195 where RANGE is set by bcm2835_pwm_set_range(). 00196 \param[in] channel The PWM channel. 0 or 1. 00197 \param[in] data Controls the PWM output ratio as a fraction of the range. 00198 Can vary from 0 to RANGE. 00199 */ 00200 void bcm2835_pwm_set_data(uint8_t channel, uint32_t data) 00201 { 00202 if (bcm2835_clk == MAP_FAILED || bcm2835_pwm == MAP_FAILED) 00203 return; /* bcm2835_init() failed or not root */ 00204 00205 if (channel == 0) 00206 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_DATA, data); 00207 else 00208 if (channel == 1) 00209 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_DATA, data); 00210 }
Generated on Tue Dec 20 2022 12:16:32 by
1.7.2