mbed API for Raspberry Pi boards.

mbedPi

This is an attempt to implement a limited number of mbed APIs for Raspberry Pi single-board computers. The project was inspired by and based on the arduPi library developed for the Arduino by Cooking Hacks .

/media/uploads/hudakz/board01.jpg

Specifications

  • Chip: Broadcom BCM2836 SoC
  • Core architecture: Quad-core ARM Cortex-A7
  • CPU frequency: 900 MHz
  • GPU: Dual Core VideoCore IV® Multimedia Co-Processor
  • Memory: 1GB LPDDR2
  • Operating System: Boots from Micro SD card, running a version of the Linux operating system
  • Power: Micro USB socket 5V, 2A

Connectors

  • Ethernet: 10/100 BaseT Ethernet socket
  • Video Output: HDMI (rev 1.3 & 1.4)
  • Audio Output: 3.5mm jack, HDMI
  • USB: 4 x USB 2.0 Connector
  • GPIO Connector: 40-pin 2.54 mm (100 mil) expansion header: 2x20 strip providing 27 GPIO pins as well as +3.3 V, +5 V and GND supply lines
  • Camera Connector: 15-pin MIPI Camera Serial Interface (CSI-2)
  • JTAG: Not populated
  • Display Connector: Display Serial Interface (DSI) 15 way flat flex cable connector with two data lanes and a clock lane
  • Memory Card Slot: Micro SDIO

GPIO connector pinout

Zoom in /media/uploads/hudakz/mbedpi_pinout02.png

Information

Only the labels printed in blue/white or green/white (i.e. p3, gpio2 ...) must be used in your code. The other labels are given as information (alternate-functions, power pins, ...).


Building programs for the Raspberry Pi with mbedPi

I use Qt Creator for development, however you can use any other IDE available on the Raspberry Pi (e.g. Geany) if you like. For a quick try:

  • Install Qt and the Qt Creator onto your Raspberry Pi. Then create a new "Blinky" Plain non-Qt C++ Project as follows: /media/uploads/hudakz/newproject.png

  • Change the main code as below:

main.cpp

#include "mbedPi.h"

int main()
{
    DigitalOut  myled(p7);

    while(1) {
        myled = 1; // LED is ON
        wait(0.2); // 200 ms
        myled = 0; // LED is OFF
        wait(1.0); // 1 sec
        printf("Blink\r\n");
    }
}


  • Copy the mbedPi.zip file into your project's folder and unzip.
  • Add the mbedPi.h and mbedPi.cpp files to your project by right clicking on the "Blinky" project and then clicking on the "Add Existing Files..." option in the local menu:

    /media/uploads/hudakz/addfiles.png

    /media/uploads/hudakz/addfiles02.png

  • Double click on Blinky.pro to open it for editing and add new libraries by inserting a new line as follows:

    /media/uploads/hudakz/libs.png

  • Compile the project.

  • Connect an LED through a 1k resistor to pin 7 and the ground on the Raspberry Pi GPIO connector.

  • Run the binary as sudo (sudo ./Blinky) and you should see the LED blinking. /media/uploads/hudakz/mbedpi_run.png

  • Press Ctrl+c to stop running the application.
Committer:
hudakz
Date:
Tue Dec 20 12:16:18 2022 +0000
Revision:
2:131555dc6fb7
Parent:
1:1f2d9982fa8c
Mbed API for Raspberry Pi boards equipped with BCM2836 SoC.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 1:1f2d9982fa8c 1 #include "mbed.h"
hudakz 1:1f2d9982fa8c 2 #include "math.h"
hudakz 1:1f2d9982fa8c 3
hudakz 1:1f2d9982fa8c 4 extern volatile uint32_t *bcm2835_pwm;
hudakz 1:1f2d9982fa8c 5 extern volatile uint32_t *bcm2835_clk;
hudakz 1:1f2d9982fa8c 6
hudakz 1:1f2d9982fa8c 7 /********************************************************************
hudakz 1:1f2d9982fa8c 8 *
hudakz 1:1f2d9982fa8c 9 * PwmOut
hudakz 1:1f2d9982fa8c 10 *
hudakz 1:1f2d9982fa8c 11 ********************************************************************/
hudakz 1:1f2d9982fa8c 12 /** Create a PwmOut connected to the specified pin
hudakz 1:1f2d9982fa8c 13 *
hudakz 1:1f2d9982fa8c 14 * @param pin PwmOut pin to connect to
hudakz 1:1f2d9982fa8c 15 */
hudakz 1:1f2d9982fa8c 16 PwmOut::PwmOut(PinName pin) :
hudakz 1:1f2d9982fa8c 17 _pwmPin(pin),
hudakz 1:1f2d9982fa8c 18 _duty_cycle(0)
hudakz 1:1f2d9982fa8c 19 {
hudakz 1:1f2d9982fa8c 20 // Set the output pin to Alt Fun 5, to allow PWM channel 0 to be output there
hudakz 1:1f2d9982fa8c 21 bcm2835_gpio_fsel(_pwmPin, BCM2835_GPIO_FSEL_ALT5);
hudakz 1:1f2d9982fa8c 22 // Set default PWM period to 20ms (usually used by servos)
hudakz 1:1f2d9982fa8c 23 period_ms(20);
hudakz 1:1f2d9982fa8c 24 }
hudakz 1:1f2d9982fa8c 25
hudakz 1:1f2d9982fa8c 26 /**
hudakz 1:1f2d9982fa8c 27 * @brief
hudakz 1:1f2d9982fa8c 28 * @note
hudakz 1:1f2d9982fa8c 29 * @param
hudakz 1:1f2d9982fa8c 30 * @retval
hudakz 1:1f2d9982fa8c 31 */
hudakz 1:1f2d9982fa8c 32 PwmOut::~PwmOut()
hudakz 1:1f2d9982fa8c 33 {
hudakz 1:1f2d9982fa8c 34 bcm2835_gpio_fsel(_pwmPin, BCM2835_GPIO_FSEL_INPT);
hudakz 1:1f2d9982fa8c 35 }
hudakz 1:1f2d9982fa8c 36
hudakz 1:1f2d9982fa8c 37 /** Set the output duty-cycle, specified as a percentage (float)
hudakz 1:1f2d9982fa8c 38 *
hudakz 1:1f2d9982fa8c 39 * @param value A floating-point value representing the output duty-cycle,
hudakz 1:1f2d9982fa8c 40 * specified as a percentage. The value should lie between
hudakz 1:1f2d9982fa8c 41 * 0.0f (representing on 0%) and 1.0f (representing on 100%).
hudakz 1:1f2d9982fa8c 42 * Values outside this range will be saturated to 0.0f or 1.0f.
hudakz 1:1f2d9982fa8c 43 */
hudakz 1:1f2d9982fa8c 44 void PwmOut::write(float value)
hudakz 1:1f2d9982fa8c 45 {
hudakz 1:1f2d9982fa8c 46 _duty_cycle = value;
hudakz 1:1f2d9982fa8c 47
hudakz 1:1f2d9982fa8c 48 if (value < 0) {
hudakz 1:1f2d9982fa8c 49 _duty_cycle = 0;
hudakz 1:1f2d9982fa8c 50 }
hudakz 1:1f2d9982fa8c 51
hudakz 1:1f2d9982fa8c 52 if (value > 1.0) {
hudakz 1:1f2d9982fa8c 53 _duty_cycle = 1.0;
hudakz 1:1f2d9982fa8c 54 }
hudakz 1:1f2d9982fa8c 55
hudakz 1:1f2d9982fa8c 56 bcm2835_pwm_set_data(PWM_CHANNEL, _duty_cycle * _range);
hudakz 1:1f2d9982fa8c 57 bcm2835_pwm_set_mode(PWM_CHANNEL, 1, 1); // channel, MARKSPACE mode, active
hudakz 1:1f2d9982fa8c 58 }
hudakz 1:1f2d9982fa8c 59
hudakz 1:1f2d9982fa8c 60 /** Return the current output duty-cycle setting, measured as a percentage (float)
hudakz 1:1f2d9982fa8c 61 *
hudakz 1:1f2d9982fa8c 62 * @returns
hudakz 1:1f2d9982fa8c 63 * A floating-point value representing the current duty-cycle being output on the pin,
hudakz 1:1f2d9982fa8c 64 * measured as a percentage. The returned value will lie between
hudakz 1:1f2d9982fa8c 65 * 0.0f (representing on 0%) and 1.0f (representing on 100%).
hudakz 1:1f2d9982fa8c 66 *
hudakz 1:1f2d9982fa8c 67 * @note
hudakz 1:1f2d9982fa8c 68 * This value may not match exactly the value set by a previous write().
hudakz 1:1f2d9982fa8c 69 */
hudakz 1:1f2d9982fa8c 70 float PwmOut::read()
hudakz 1:1f2d9982fa8c 71 {
hudakz 1:1f2d9982fa8c 72 return _duty_cycle;
hudakz 1:1f2d9982fa8c 73 }
hudakz 1:1f2d9982fa8c 74
hudakz 1:1f2d9982fa8c 75 /** Set the PWM period, specified in bcm2835PWMPulseWidth (micro/nano seconds), keeping the duty cycle the same.
hudakz 1:1f2d9982fa8c 76 * @note Sets clock divider according to the required period.
hudakz 1:1f2d9982fa8c 77 * @param period Change the period of a PWM signal. The allowed values are:
hudakz 1:1f2d9982fa8c 78 * BCM2835_PWM_PERIOD_833_NS -> 833.33 ns = 1200.000 kHz
hudakz 1:1f2d9982fa8c 79 */
hudakz 1:1f2d9982fa8c 80 void PwmOut::period_ms(int period_ms)
hudakz 1:1f2d9982fa8c 81 {
hudakz 1:1f2d9982fa8c 82 _range = period_ms * 1200;
hudakz 1:1f2d9982fa8c 83 bcm2835_pwm_set_clock(BCM2835_PWM_PERIOD_833_NS); // clock pulse = 833.33 ns
hudakz 1:1f2d9982fa8c 84 bcm2835_pwm_set_range(PWM_CHANNEL, _range);
hudakz 1:1f2d9982fa8c 85 }
hudakz 1:1f2d9982fa8c 86
hudakz 1:1f2d9982fa8c 87 /** Set the PWM period, specified in bcm2835PWMPulseWidth (micro/nano seconds), keeping the duty cycle the same.
hudakz 1:1f2d9982fa8c 88 * @note Sets clock divider according to the required period.
hudakz 1:1f2d9982fa8c 89 * @param period Change the period of a PWM signal. The allowed values are:
hudakz 1:1f2d9982fa8c 90 * BCM2835_PWM_PERIOD_104_NS -> 104.16 ns = 9600.000 kHz
hudakz 1:1f2d9982fa8c 91 */
hudakz 1:1f2d9982fa8c 92 void PwmOut::period_us(int period_us)
hudakz 1:1f2d9982fa8c 93 {
hudakz 1:1f2d9982fa8c 94 _range = rintf(period_us * 9.600f);
hudakz 1:1f2d9982fa8c 95 bcm2835_pwm_set_clock(BCM2835_PWM_PERIOD_104_NS);
hudakz 1:1f2d9982fa8c 96 bcm2835_pwm_set_range(PWM_CHANNEL, _range);
hudakz 1:1f2d9982fa8c 97 }
hudakz 1:1f2d9982fa8c 98
hudakz 1:1f2d9982fa8c 99 /***********************************************************************
hudakz 1:1f2d9982fa8c 100 *
hudakz 1:1f2d9982fa8c 101 * PWM
hudakz 1:1f2d9982fa8c 102 *
hudakz 1:1f2d9982fa8c 103 ***********************************************************************/
hudakz 1:1f2d9982fa8c 104
hudakz 1:1f2d9982fa8c 105 /*! Sets the PWM clock divisor,
hudakz 1:1f2d9982fa8c 106 to control the basic PWM pulse widths.
hudakz 1:1f2d9982fa8c 107 \param[in] divisor Divides the basic 19.2MHz PWM clock. You can use one of the common
hudakz 1:1f2d9982fa8c 108 values BCM2835_PWM_CLOCK_DIVIDER_* in \ref bcm2835PWMClockDivider
hudakz 1:1f2d9982fa8c 109 */
hudakz 1:1f2d9982fa8c 110 void bcm2835_pwm_set_clock(uint32_t divisor)
hudakz 1:1f2d9982fa8c 111 {
hudakz 1:1f2d9982fa8c 112 if (bcm2835_clk == MAP_FAILED || bcm2835_pwm == MAP_FAILED) {
hudakz 1:1f2d9982fa8c 113 return; /* bcm2835_init() failed or not root */
hudakz 1:1f2d9982fa8c 114 }
hudakz 1:1f2d9982fa8c 115
hudakz 1:1f2d9982fa8c 116 /* From Gerts code */
hudakz 1:1f2d9982fa8c 117 divisor &= 0xfff;
hudakz 1:1f2d9982fa8c 118
hudakz 1:1f2d9982fa8c 119 /* Stop PWM clock */
hudakz 1:1f2d9982fa8c 120 bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x01);
hudakz 1:1f2d9982fa8c 121 bcm2835_delay(110); /* Prevents clock going slow */
hudakz 1:1f2d9982fa8c 122
hudakz 1:1f2d9982fa8c 123 /* Wait for the clock to be not busy */
hudakz 1:1f2d9982fa8c 124 while ((bcm2835_peri_read(bcm2835_clk + BCM2835_PWMCLK_CNTL) & 0x80) != 0)
hudakz 1:1f2d9982fa8c 125 bcm2835_delay(1);
hudakz 1:1f2d9982fa8c 126
hudakz 1:1f2d9982fa8c 127 /* set the clock divider and enable PWM clock */
hudakz 1:1f2d9982fa8c 128 bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_DIV, BCM2835_PWM_PASSWRD | (divisor << 12));
hudakz 1:1f2d9982fa8c 129 bcm2835_peri_write(bcm2835_clk + BCM2835_PWMCLK_CNTL, BCM2835_PWM_PASSWRD | 0x11); /* Source=osc and enable */
hudakz 1:1f2d9982fa8c 130 }
hudakz 1:1f2d9982fa8c 131
hudakz 1:1f2d9982fa8c 132 /*! Sets the mode of the given PWM channel,
hudakz 1:1f2d9982fa8c 133 allowing you to control the PWM mode and enable/disable that channel
hudakz 1:1f2d9982fa8c 134 \param[in] channel The PWM channel. 0 or 1.
hudakz 1:1f2d9982fa8c 135 \param[in] markspace Set true if you want Mark-Space mode. 0 for Balanced mode.
hudakz 1:1f2d9982fa8c 136 \param[in] enabled Set true to enable this channel and produce PWM pulses.
hudakz 1:1f2d9982fa8c 137 */
hudakz 1:1f2d9982fa8c 138 void bcm2835_pwm_set_mode(uint8_t channel, uint8_t markspace, uint8_t enabled)
hudakz 1:1f2d9982fa8c 139 {
hudakz 1:1f2d9982fa8c 140 if (bcm2835_clk == MAP_FAILED || bcm2835_pwm == MAP_FAILED) {
hudakz 1:1f2d9982fa8c 141 return; /* bcm2835_init() failed or not root */
hudakz 1:1f2d9982fa8c 142 }
hudakz 1:1f2d9982fa8c 143
hudakz 1:1f2d9982fa8c 144 /* If you use the barrier here, wierd things happen, and the commands dont work */
hudakz 1:1f2d9982fa8c 145
hudakz 1:1f2d9982fa8c 146 /*
hudakz 1:1f2d9982fa8c 147 uint32_t control = bcm2835_peri_read(bcm2835_pwm + BCM2835_PWM_CONTROL);
hudakz 1:1f2d9982fa8c 148
hudakz 1:1f2d9982fa8c 149 if (channel == 0) {
hudakz 1:1f2d9982fa8c 150 if (markspace)
hudakz 1:1f2d9982fa8c 151 control |= BCM2835_PWM0_MS_MODE;
hudakz 1:1f2d9982fa8c 152 else
hudakz 1:1f2d9982fa8c 153 control &= ~BCM2835_PWM0_MS_MODE;
hudakz 1:1f2d9982fa8c 154 if (enabled)
hudakz 1:1f2d9982fa8c 155 control |= BCM2835_PWM0_ENABLE;
hudakz 1:1f2d9982fa8c 156 else
hudakz 1:1f2d9982fa8c 157 control &= ~BCM2835_PWM0_ENABLE;
hudakz 1:1f2d9982fa8c 158 }
hudakz 1:1f2d9982fa8c 159 else
hudakz 1:1f2d9982fa8c 160 if (channel == 1) {
hudakz 1:1f2d9982fa8c 161 if (markspace)
hudakz 1:1f2d9982fa8c 162 control |= BCM2835_PWM1_MS_MODE;
hudakz 1:1f2d9982fa8c 163 else
hudakz 1:1f2d9982fa8c 164 control &= ~BCM2835_PWM1_MS_MODE;
hudakz 1:1f2d9982fa8c 165 if (enabled)
hudakz 1:1f2d9982fa8c 166 control |= BCM2835_PWM1_ENABLE;
hudakz 1:1f2d9982fa8c 167 else
hudakz 1:1f2d9982fa8c 168 control &= ~BCM2835_PWM1_ENABLE;
hudakz 1:1f2d9982fa8c 169 }
hudakz 1:1f2d9982fa8c 170
hudakz 1:1f2d9982fa8c 171 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, control);
hudakz 1:1f2d9982fa8c 172 */
hudakz 1:1f2d9982fa8c 173
hudakz 1:1f2d9982fa8c 174 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM_CONTROL, BCM2835_PWM0_ENABLE | BCM2835_PWM1_ENABLE | BCM2835_PWM0_MS_MODE | BCM2835_PWM1_MS_MODE);
hudakz 1:1f2d9982fa8c 175 }
hudakz 1:1f2d9982fa8c 176
hudakz 1:1f2d9982fa8c 177 /*! Sets the maximum range of the PWM output.
hudakz 1:1f2d9982fa8c 178 The data value can vary between 0 and this range to control PWM output
hudakz 1:1f2d9982fa8c 179 \param[in] channel The PWM channel. 0 or 1.
hudakz 1:1f2d9982fa8c 180 \param[in] range The maximum value permitted for DATA.
hudakz 1:1f2d9982fa8c 181 */
hudakz 1:1f2d9982fa8c 182 void bcm2835_pwm_set_range(uint8_t channel, uint32_t range)
hudakz 1:1f2d9982fa8c 183 {
hudakz 1:1f2d9982fa8c 184 if (bcm2835_clk == MAP_FAILED || bcm2835_pwm == MAP_FAILED)
hudakz 1:1f2d9982fa8c 185 return; /* bcm2835_init() failed or not root */
hudakz 1:1f2d9982fa8c 186
hudakz 1:1f2d9982fa8c 187 if (channel == 0)
hudakz 1:1f2d9982fa8c 188 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_RANGE, range);
hudakz 1:1f2d9982fa8c 189 else
hudakz 1:1f2d9982fa8c 190 if (channel == 1)
hudakz 1:1f2d9982fa8c 191 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_RANGE, range);
hudakz 1:1f2d9982fa8c 192 }
hudakz 1:1f2d9982fa8c 193
hudakz 1:1f2d9982fa8c 194 /*! Sets the PWM pulse ratio to emit to DATA/RANGE,
hudakz 1:1f2d9982fa8c 195 where RANGE is set by bcm2835_pwm_set_range().
hudakz 1:1f2d9982fa8c 196 \param[in] channel The PWM channel. 0 or 1.
hudakz 1:1f2d9982fa8c 197 \param[in] data Controls the PWM output ratio as a fraction of the range.
hudakz 1:1f2d9982fa8c 198 Can vary from 0 to RANGE.
hudakz 1:1f2d9982fa8c 199 */
hudakz 1:1f2d9982fa8c 200 void bcm2835_pwm_set_data(uint8_t channel, uint32_t data)
hudakz 1:1f2d9982fa8c 201 {
hudakz 1:1f2d9982fa8c 202 if (bcm2835_clk == MAP_FAILED || bcm2835_pwm == MAP_FAILED)
hudakz 1:1f2d9982fa8c 203 return; /* bcm2835_init() failed or not root */
hudakz 1:1f2d9982fa8c 204
hudakz 1:1f2d9982fa8c 205 if (channel == 0)
hudakz 1:1f2d9982fa8c 206 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM0_DATA, data);
hudakz 1:1f2d9982fa8c 207 else
hudakz 1:1f2d9982fa8c 208 if (channel == 1)
hudakz 1:1f2d9982fa8c 209 bcm2835_peri_write_nb(bcm2835_pwm + BCM2835_PWM1_DATA, data);
hudakz 1:1f2d9982fa8c 210 }