Monday, June 13, 2016

VHDL Processes for Pulsing Multiple Lasers at Different Frequencies on Altera FPGA


DE1-SoC GPIO Pins connected to 780nm Infrared Laser Diodes, 660nm Red Laser Diodes, and Oscilloscope

The following VHDL processes pulse the GPIO pins at different frequencies on the Altera DE1-SoC using multiple Phase-Locked Loops.  Multiple Infrared Laser Diodes are connected to the GPIO banks and pulsed at a 50% duty cycle with 16mA across 3.3V.  Each GPIO bank on the DE1-SoC has 36 pins. Pin 1 is pulsed at 20hz from GPIO bank 0, and pins 0 and 1 are pulsed at 30hz from GPIO bank 1.  A direct mode PLL with locked output was configured using the Altera Quartus Prime MegaWizard.  The PLL reference clock frequency is set to 50mhz, the output clock frequency is set to 50mhz, and the duty cycle is set to 50%.  The pin mappings for GPIO banks 0 and 1 are documented on the DE1-SoC datasheet.

Pulsed Laser Diodes via GPIO pins on DE1-SoC FPGA

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

- --Copyright (C) 2016. Bryan R. Hinton
- --All rights reserved.
- --
- --Redistribution and use in source and binary forms, with or without
- --modification, are permitted provided that the following conditions
- --are met:
- --1. Redistributions of source code must retain the above copyright
- --   notice, this list of conditions and the following disclaimer.
- --2. Redistributions in binary form must reproduce the above copyright
- --   notice, this list of conditions and the following disclaimer in the
- --   documentation  and/or other materials provided with the distribution.
- --3. Neither the names of the copyright holders nor the names of any
- --   contributors may be used to endorse or promote products derived from this
- --   software without specific prior written permission.
- --
- --THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- --AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- --IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- --ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- --LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- --CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- --SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- --INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- --CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- --ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- --POSSIBILITY OF SUCH DAMAGE.

- ---------------------
- -- CLOCK A PROCESS --
- ---------------------
- -- INPUT: direct mode pll with locked output 
- -- and reference clock frequency set to 50mhz, 
- -- output clock frequency set to 50mhz with 50% duty 
- -- cycle and output frequency scaled by freq divider constant
- -------------------------------------------------------------
clk_a_process : process (lkd_pll_clk_a)
begin
 if rising_edge(lkd_pll_clk_a) then
  if (cycle_ctr_a < FREQ_A_DIVIDER) then
   cycle_ctr_a <= cycle_ctr_a + 1;
  else
   cycle_ctr_a <= 0;
  end if;
 end if;
end process clk_a_process;
 
- ---------------------
- -- CLOCK B PROCESS --
- ---------------------
- -- INPUT: direct mode pll with locked output 
- -- and reference clock frequency set to 50mhz, 
- -- output clock frequency set to 50mhz with 50% duty 
- -- cycle and output frequency scaled by freq divider constant
- -------------------------------------------------------------
clk_b_process : process (lkd_pll_clk_b)
begin
      if rising_edge(lkd_pll_clk_b) then
  if (cycle_ctr_b < FREQ_B_DIVIDER) then
   cycle_ctr_b <= cycle_ctr_b + 1;
  else
   cycle_ctr_b <= 0;
          end if;
     end if;
end process clk_b_process;
 
- ---------------------
- -- GPIO A PROCESS --
- ---------------------
- -- INPUT: direct mode pll with locked output
- --------------------------------------------------------- 
gpio_a_process : process (lkd_pll_clk_a)
begin
 if rising_edge(lkd_pll_clk_a) then
         if (cycle_ctr_a = 0) then
   -- toggle gpio pin1 from gpio_0
   gpio_sig_0(1) <= NOT gpio_sig_0(1);
          end if;
       end if;
end process gpio_a_process;

- ---------------------
- -- GPIO B PROCESS --
- ---------------------
- -- INPUT: direct mode pll with locked output
- ---------------------------------------------------------
gpio_b_process : process (lkd_pll_clk_b)
begin
 if rising_edge(lkd_pll_clk_b) then
         if (cycle_ctr_b = 0) then
   -- toggle gpio pins 0 and 1 from gpio_1
   gpio_sig_1 <= NOT gpio_sig_1(1 downto 0);
          end if;
       end if;
end process gpio_b_process;
 
GPIO_0 <= gpio_sig_0;
GPIO_1 <= gpio_sig_1;

end gpioarch;
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQIcBAEBAgAGBQJXX2UDAAoJEPbndIT4b5KAnYYP/RgR8RGP7JPgC6CIO+gCQxe7
QXrRV7ea9vZCSuF5stCVY1UbEOfSv2jcufUc5Bg12Ddi+d9NLLPJa4/jL+ZRtwet
G+sIGcmxmviBReQCU6zVWOyPBzwoD3EJJdkHf1KtZUmq3pJKNsYefKzqIyzfhJ3t
mOtShH1mCMqxA4RD8wqfGmA1V1U3kOGd3APWnby1MKvbWaDLbNptZLovtweaw3F5
zgNDOMdCwFZpMScVHCW2tiZyoFHnMyhPes7uaBgj3CAQLRgIVKr7jUnU6HIWh4Ag
6be78TT22Zmf32+udQHzKjKcoYpMVatuBX6zY+sJ8jY92PypDi7u0wtHt+G3Hrht
XUW69s3tjR4JWw4qFX+JSYl8b2sEzDEeGAMJeB9r0+mCUH5C3f1cNWp5k1Rsne3z
3djluxQJzzZ+icvYrVz50sQyzqx1TCNJIW7tY3Va5kjF/jmH7ubbGP9YkPy5uoKt
ZNyI971A4KC5haov4PiRA8J7aUG+hNkhadY1YI8AIoP5zlk1im7vahE44SVA777r
ATLj64gzHoVdOSsEqY9ju68XBNvLDWeyN4u4AQD/yiW+9dnD324q3jan9Vx+6jWX
Y6LYmR/6HOPb7yPGw/4W11oDZ3RwfnBCrmuUYzYWC2Y0NuDebrskzTM2tXXU3gyq
qUWJiP6qmL/nsf72nBa1
=nJWe
-----END PGP SIGNATURE-----


DE1-SoC GPIO Bank 0 Pin 1

DE1-SoC GPIO Bank 1 Pins 0 and 1

Thursday, June 2, 2016

FPGA Audio Processing with the Cyclone V Dual-Core ARM Cortex-A9

The DE1-SoC FPGA Development board from Terasic is powered by an integrated Altera Cyclone V FPGA and ARM MPCore Cortex-A9 processor.  The FPGA and ARM core are connected by a high-speed interconnect fabric so you can boot Linux on the ARM core and then talk to the FPGA.
The below configuration was built from the Terasic Design Reference sources.

The DE1-SoC board below has been programmed via Quartus Prime running on Fedora 23, 64-bit Linux.  The FPGA bitstream was compiled from the Terasic Audio codec design reference.  After the bitstream was loaded on to the FPGA over the USB blaster II interface, the NIOS II command shell was used to load the NIOS II software image onto the chip.  A menu-driven, debug interface is running from a terminal on the host via the NIOS II shell with the target connected over the USB Blaster II interface.

A low-level hardware abstraction layer was programmed in C to configure the on-board audio codec chip.  The NIOS II chip is stored in on-chip memory and a PLL driven, clock signal is fed into the audio chip. The Verilog code for the hardware design was generated from Qsys.  The design supports configurable sample rates, mic in, and line in/out.

Additional components are connected to the DE1-SoC board in this photo.  The Linear DC934A (LTC2607) DAC is connected to the DE1-SoC and an oscilloscope is connected to the ground and vref pins on the DAC.

The DC934A features an LTC2607 16-Bit Dual DAC with i2c interface and an LTC2422 2-Channel 20-Bit uPower No Latency Delta Sigma ADC.

3.5mm audio cables are connected to the mic in and line out ports, respectively.  The DE1-SoC is connected to an external display over VGA so that a local console can be managed via a connected keyboard and mouse when Linux is booted from uSD.

With GPIO pins accessible via the GPIO 0 and 1 breakouts, external LEDs can be pulsed directly from the Hard Processor System (HPS), FPGA, or the FPGA via the HPS.

Tuesday, May 31, 2016

Pulse Any GPIO Pin with the ARM System Timer from Bare Metal on the Raspberry Pi 3

650nm 5mW Red Laser Pulsed at 20Hz from Bare Metal on a Raspberry Pi 3
Sony NoIR 8mp Camera Module for Raspberry Pi Model 3 B


The ARM system timer register can be used for creating a clock to pulse the GPIO pins on the Raspberry Pi 3 at a predetermined frequency.

In the below code, a 5v, 650nm 5mW Red Laser diode is pulsed at 20Hz on GPIO pin 22 via bare metal C code on the Raspberry Pi 3.

$ arm-none-eabi-gcc -O2 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv8-a -mtune=cortex-a53 -nostartfiles pulse.c -o kernel.elf

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

/* Pulse a GPIO pin using the ARM system timer via Bare Metal on the Raspberry Pi 3 */
 * Copyright (C) Bryan R. Hinton 05-31-2016

 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

/* for rpi3, base addresses can be calculcated by subtracting 0x3f000000 from the 
/* base address in the ARM Peripherals data sheet for the BCM2835 */
#define GPIO_BASE    0x3f200000  /* GPIO base address */
#define ARM_SYSTIMER_CLO 0x3f003004  /* ARM System Timer Counter Lower 32 bits */
#define GPSET0_OFFSET    0x07        /* GPIO Pin Output Set 0 Offset */
#define GPCLR0_OFFSET    0x0a        /* GPIO Pin Output Clear 0 Offset */
#define MAXPINCNT   3 
#define TIMEOUT   0xC350     /* 0.05 seconds = 20hz*/

int main(void)
{
   /* static const array of usable gpio pins on raspberry pi 3 */
   static const unsigned int gpiopin[MAXPINCNT] =  {22,17,4};

   /* pin index, pin 22 */
   int pinidx = 0; 

   /* lower 32 bits of current system timer value */
   unsigned int cur_tval; 

   /* setup gpio base address */
   volatile unsigned int *gpio_base = (unsigned int *)GPIO_BASE;

   /* setup system timer base address */
   volatile unsigned int *systimer_clo = (unsigned int *)ARM_SYSTIMER_CLO;

   /* set gpio(n) for input by clearing bits (GPIO_PIN%10)*3 GPFSEL(N)
    * where (GPIO_PIN%10)*3 is FSEL(N) or the three configuration bits for GPIO(N)
    * 1. Find the gpio function select(gpfsel) register for the GPIO pin.
    *  Pins 0-9 use gpfsel 0
    *  Pins 10-19 use gpfsel 1
    *  Pins 20-29 use gpfsel 2
    *  Pins 30-39 use gpfsel 3
    *  Pins 40-49 use gpfsel 4
    *  Pins 50-53 use gpfsel 5
    * 2. Set or Clear the function select bits in that register for the designated gpio pin
    *  gpio pin 5 is set for input in gpfsel 0 by clearing bits 15-17  
    *  gpio pin 5 is set for output in gpfsel 0 by setting bits 15-17 to 001  
    *  gpio pin 22 is set for input in gpfsel 2 by clearing bits 6-8  
    *  gpio pin 22 is set for output in gpfsel 2 by setting bits 6-8 to 001 */

   /*  set gpiopin[idx] for input by clearing bits k,k+1,K+2 in gpfsel n.
    *  gpfsel(2) gpiopin 22 bit string mask for gp input 11111111111111111111111000111111 (rval)
    *  gpfsel(0) gpiopin 3 bit string mask for gp input 11111111111111111111000111111111 (rval) */
    *(gpio_base + (*(gpiopin+pinidx)%10)) &= ~(7  < ((*(gpiopin+pinidx)%10)*3));

   /*  set gpiopin[idx] for output by setting bits k,k+1,k+2 to 001 in gpfsel n.
    *  gpfsel(2) gpiopin 22 bit string mask for gp output 00000000000000000000000001000000 (rval)
    *  gpfsel(2) gpiopin 3 bit string mask for gp output 00000000000000000000001000000000 (rval) */
    *(gpio_base + (*(gpiopin+pinidx)%10)) |= (1 << ((*(gpiopin+pinidx)%10)*3));
 
    /* iterate through each usable gpio pin and pulse it */
    /* one single iteration of this loop equals the frequency of the timer or 20hz for this example */
    while(1) {

 /* set gpio pin */
       *(gpio_base + GPSET0_OFFSET) |= (1 << (*(gpiopin+pinidx)));

 for(;;) {
  /* prefetch current lower 32 bit val of read only timer register */
  cur_tval = *(systimer_clo); 
  /* if timer val was just reset, loop, 1/2*period or half cycle mark */
  if((cur_tval & TIMEOUT) == TIMEOUT)
   break;
 }
        /* clear gpio pin */
 *(gpio_base + GPCLR0_OFFSET) &= (1 << (*(gpiopin+pinidx)));

 for(;;) {
  /* prefetch current lower 32 bit val of read only timer register */
  cur_tval = *(systimer_clo); 
  /* if timer val is zero, loop, 1/2*period or half cycle mark */
  if((cur_tval & TIMEOUT) == 0)
   break;
 }
    }
}
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQIcBAEBAgAGBQJXTml/AAoJEPbndIT4b5KAHuoQALeHhpc32TSfKt632Vwn92Zv
cd93o6a9lnQLgBLYUCfW1y23UUgoUGgd7aXm2ssUjt9vwdqj5AZSq7lNcNdOb5nM
PR81A1VVu8QuOj/gI6sMOLotcbI70hFZWqD3x8CNTYQXTz1J8wPae85oY3rEmSxz
a8U43QBpx98RcHZIsc52MiPDzPTiqBSzaPsJMFQqlUDSo9T8G1J2BqLnL35dI1Yw
7jr8vZGNDHcujLFIIt/GY24M71Cyw1J+VqxAguvgzebc+pj/4kKTG8AKXueSed0A
ztE5DOQDOqs+HmNEkF/LU+SASvQz3czl0dOhIbhO+HFVDjlX7Qv7I/iLwQ3hWbef
XROdoP2wWRR8Bs7fFTKtaQ5+32O31xdovwtmUXCwGT4i0cckD/97LND8ntdpiA8n
w6ek19QZvxVIeZ5Mm4H7C/zbLN3n6OEstfxRzHpmgqntOcrCSuKhtx5em6XGfhLT
uJv4Xgo35eh5aCKV2GsOxLE9eymHVMQpV6GQGCIeMCIxawmlRu2k/whpBR/u1F/l
4CyYhXHoCpEP6Lr3YFiZPbYueRySo9uPkz77u/RhmnMamSytnGCiyYr5BhpeZYMu
OwtjdN8vPFHged4hroDAC4RKdGD/gVPKqvlZ9zgCMIvlzLWNgJdev/iVXqOOf1FW
ASSma5+BFeK5VUL1ITjI
=Wxx/
-----END PGP SIGNATURE-----

Monday, May 30, 2016

Bare Metal C with the Raspberry Pi 3 and Sony 8mp NoIR camera

780nm IR Laser Diode pulsed at ~20.2Hz
Sony NoIR 8mp Camera Module for Raspberry Pi 3
Pulsing a laser diode at a frequency over 38 to 40 megahertz from bare metal necessitates an FPGA, microcontroller board with an RTOS running on it, or a dedicated circuit.  Some of the laser diodes that were tested required a simple voltage divider circuit. Others stayed well under 5v and 20ma.

Several different methods of pulsing the GPIO pins were tested; memory mapped IO where the physical ARM peripheral base addresses were mapped into Linux user space via virtual addressing, C and python user space programs that link against user space dynamically linked libraries which in turn read and write the ARM peripheral address space to toggle the GPIO pins, a device driver that disables interrupts and writes to the underlying ARM peripheral address space after being called from a syscall in user space, and bare metal C code that directly writes to the ARM peripheral address space.
780nm IR Laser Diode pulsed at ~20.2Hz
 Sony NoIR 8mp Camera Module

These images were shot using the Sony NoIR 8mp Camera module for the Raspberry Pi 3.

850nm IR Laser Continuous Wave
Sony NoIR 8mp Camera Module





Friday, May 27, 2016

Pulse any GPIO Pin from Bare Metal on a Raspberry Pi 3

Any of the usable GPIO pins on the Raspberry Pi model B can be pulsed from bare metal with a few changes to the code from the prior post. The following commands were used to compile this code on the Raspberry Pi 3 Model B.

$ arm-none-eabi-gcc -O2 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv8-a -mtune=cortex-a53 \ -nostartfiles pulse.c -o kernel.elf






-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

/* 
 * Bare Metal program for toggling any GPIO pin on the Raspberry Pi 3 Model B
 * Copyright (C) 05-27-2016  Bryan R. Hinton
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
#define GPIO_BASE  0x3f200000 /* GPIO base address for rpi3 */
#define GPSET0_OFFSET  0x07    /* GPIO Pin Output Set 0 Offset */
#define GPCLR0_OFFSET  0x0a    /* GPIO Pin Output Clear 0 Offset */
#define MAXPINCNT 26

int main(void)
{
   /* static const array of usable gpio pins on raspberry pi 3 */
   static const unsigned int gpiopin[MAXPINCNT] =  {2,3,4,17,27,22,10,9,11,5,6,\
                                   13,19,26,14,15,18,23,24,25,8,7,12,16,20,21};

   /* select pin index */
   int pinidx = 1;

   /* setup gpio base address */
   volatile unsigned int *gpio_base = (unsigned int *)GPIO_BASE;

  /* set gpio(n) for input by clearing bits (GPIO_PIN%10)*3 GPFSEL(N)
   * where (GPIO_PIN%10)*3 is FSEL(N) or the three configuration bits for GPIO(N)
   * 1. Find the gpio function select(gpfsel) register for the GPIO pin.
   *  Pins 0-9 use gpfsel 0
   *  Pins 10-19 use gpfsel 1
   *  Pins 20-29 use gpfsel 2
   *  Pins 30-39 use gpfsel 3
   *  Pins 40-49 use gpfsel 4
   *  Pins 50-53 use gpfsel 5
   * 2. Set or Clear the function select bits in that register for the designated gpio pin
   *  gpio pin 5 is set for input in gpfsel 0 by clearing bits 15-17  
   *  gpio pin 5 is set for output in gpfsel 0 by setting bits 15-17 to 001  
   *  gpio pin 22 is set for input in gpfsel 2 by clearing bits 6-8  
   *  gpio pin 22 is set for output in gpfsel 2 by setting bits 6-8 to 001 */

  /*  set gpiopin[pinidx] for input by clearing bits k,k+1,K+2 in gpfsel n.
   *  gpfsel(2) gpiopin 22 bit string mask for gp input 11111111111111111111111000111111 (rval)
   *  gpfsel(0) gpiopin 3 bit string mask for gp input 11111111111111111111000111111111 (rval) */
   *(gpio_base + (*(gpiopin+pinidx)%10)) &= ~(7  < ((*(gpiopin+pinidx)%10)*3));

  /*  set gpiopin[pinidx] for output by setting bits k,k+1,k+2 to 001 in gpfsel n.
   *  gpfsel(2) gpiopin 22 bit string mask for gp output 00000000000000000000000001000000 (rval)
   *  gpfsel(2) gpiopin 3 bit string mask for gp output 00000000000000000000001000000000 (rval) */
   *(gpio_base + (*(gpiopin+pinidx)%10)) |= (1 << ((*(gpiopin+pinidx)%10)*3));

   /* iterate through each usable gpio pin and pulse it */
   while(1) {

      /* set gpio pin */
      *(gpio_base + GPSET0_OFFSET) |= (1 << (*(gpiopin+pinidx)));

      /* clear gpio pin */
      *(gpio_base + GPCLR0_OFFSET) &= (1 << (*(gpiopin+pinidx)));
   }
}
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQIcBAEBAgAGBQJXSN4dAAoJEKJTsaf+3Ky+11EP/3uf38uUC7SbyAE5Jp0SwfMC
YhIgC92Erb4A5OKK9dOx7FzCgwCdU7ifoCjPcjZonxkFqMt/lEpFa7MaqHqpsUWt
vxHmXHx5V/9WCVAy8acunAlVcWhimls9dqJni5gfIpSH80C1Nvph14UTgYB3ejs+
onCsipkIqK4/YOih58ZNqHYOleVvX8DpQvnY+mGgqYzuhITtOddgYmgmwK3FOy6s
1EjP3xLo3ovs1FGX11j/ZRdlpoh1MnivJtUNIuTXMv+4BYKv8asQbDdukkYYRM+L
VEulKrjYveJZtiWElZ0csL1sMoeBZV4pWsKhtriWcS08XsscqJXc2D8RrlgbrR08
MhoKYoXUZcAxH6pXJC6KkI/pIITKkhqzO+XgoOL+VLiUqldMu00sWUuk9muHx4EH
jtSxpI9aQZOiNwDe+iomOsIfwFA5Zon6TAga0EesMUDGRt9/qlYM2y7nwooOZAkD
/Jinz/QmYp9+bRkxDMUiBm8zwa4o6EkfycJ33Sye4fviwmjwUgftBUPKWgCDldac
Qk7VbMSzjlyJ/wPOOIGEppDcQXwwH87d1TOwy+sr2OLjO2eZpAs7P6ZgV9YNcVvA
CZKGPD6fZm5jkVYjNjbxyHk517uuCIUWYptCFFPUnNbCPvLl3klsBasStG+7HJCP
/IPgYPuswmijA06lAC4I
=y2H9
-----END PGP SIGNATURE-----


Github Repo

Thursday, May 26, 2016

Pulse an IR Laser from Bare Metal on the Raspberry Pi 3



Pulsing an LED or Laser from code running on bare metal is faster than pulsing the LED or Laser from userspace on a preemptive, time sliced operating system such as Linux.  The GPIO pins on the Raspberry Pi 3 model B can be toggled via bare metal code.  The following code was cross-compiled on Linux using the latest generic ARM toolchain for the Quad Core Cortex-A53 processor on the Raspberry Pi 3 model B.


The Cortex-A53 supports the ARMv8-A Architecture.  The following commands were used to compile this code on the Raspberry Pi 3. Please note, you will need to pull bootcode.bin and start.elf from the Raspberry Pi github master branch.





$ arm-none-eabi-gcc -O2 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv8-a -mtune=cortex-a53 \ -nostartfiles pulse.c -o kernel.elf
$ arm-none-eabi-objcopy kernel.elf -O binary kernel7.img
$ cp kernel7.img kernel.img



-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


/* 
 * Bare Metal program for toggling a GPIO pin on the Raspberry Pi 3 Model B
 * Copyright (C) 05-26-2016  Bryan R. Hinton
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.

 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define GPIO_BASE  0x3f200000 /* GPIO base address for rpi3 */
#define GPSET0_OFFSET  0x07    /* GPIO Pin Output Set 0 Offset */
#define GPCLR0_OFFSET  0x0a    /* GPIO Pin Output Clear 0 Offset */
#define GPFSEL2_OFFSET  0x02    /* GPFSEL2 Offset */
#define GPFSEL_OFFSET GPFSEL2_OFFSET
#define GPIO_PIN 22

int main(void)
{
   /* setup gpio base address */
   volatile unsigned int *gpio_base = (unsigned int *)GPIO_BASE;
  
  /* clear gpio(n) for input by setting bits (GPIO_PIN%10)*3 to 000 in GPFSEL(N)
   * where (GPIO_PIN%10)*3 is FSEL(N) or the three configuration bits for GPIO(N)
   */
  *(gpio_base + GPFSEL2_OFFSET) &= ~(7 << (GPFSEL2_OFFSET*3));
  /* set gpio(n) for output by setting bits (GPIO_PIN%10)*3 to 001 in GPFSEL(N)
   * for FSEL(N) 
   */
  *(gpio_base + GPFSEL2_OFFSET) |= (1 << ((GPFSEL2_OFFSET)*3));

   while(1) {
      /* set gpio pin */
      *(gpio_base + GPSET0_OFFSET) |= (1 << GPIO_PIN);
      /* clear gpio pin */
      *(gpio_base + GPCLR0_OFFSET) &= (1 << GPIO_PIN);
  }
}
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1

iQIcBAEBAgAGBQJXR79kAAoJEKJTsaf+3Ky+ZGcP/RwA6WePGwbcSrbFIERqIdHG
hrIA48VpwUQ/SIVvKyH93fvTzlqfrSrHzFbI9IUmqtZgWOah1X/dCfnFSrNRTn4x
6ZaZgCADlKCuarC/7tuMLkqtP6cOuvH0rWsKAtEIkmSyFPp22GttkkiHrW6ZvKZd
Z9AybVJ5XemzYVwolnkdFFb8C6oFwijaKqbkUrlHFEvvyILnsrnNhKo18iQ3dEaH
fvZCwDRMYOrHM8XqMb0ZVP27UBAuXlkaFElNeHs0iG1qmS82C7fFRwlAQe9PWo87
0xzYyeP93+pQFCo5lRtdRsm3w9R6gkhliKztyRVROiL0onzi/MGc850JX9TkWwP+
z1+uSJNf93THe9vNc9SMiuMPmx2SjCTT2WoVKFJ31K8PYvGA7nfOD/s0msV02WKr
hnPVDdQDzGSYio4uIs5J4QDvNgfFjxMZSvZvWgT/vuI3KZVxwVDU1VQxAtlx3BuA
CCBSbVa0X2Wum6XQqafZuXd11I3IIMoFXFHIH1VwLdxRYVWBtC8Bj41hR9iiOKXo
3omOCve73GozpgDMaW53BoyFqNYbyqzRN6JUtvbO8ST6a/szWARZcVOI4bwHZPIB
cSSQ75YszsNz7rSTGMdyNOy4V4e7YrfSyBn/Arc1FWmtPddU55DEjXy5mqiUIep6
lsPoPUfgviuYvzqtEVxR
=RCpP
-----END PGP SIGNATURE-----

Sunday, May 22, 2016

Pulse an IR Laser at Multiple Frequencies with the Raspberry Pi 3


The following C program pulses an Infrared laser at multiple frequencies using the GPIO pin on the Raspberry Pi 3.  The program can be compiled on the Raspberry Pi 3 and is dynamically linked against the Wiring Pi library.

Please note, preemptive time slicing in the stock Raspbian kernel restricts the frequency at which the laser can be pulsed.







/* 
Copyright (c) 2016, Bryan R. Hinton
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <wiringPi.h>

/* set mode of gpio pin on rpi3 */
void gpio_setup(const unsigned int *gpiopin, int mode)
{
pinMode(*gpiopin, mode);
}

/* toggle laser on gpio pin at two different frequencies */
void gpio_toggle_pin(const unsigned int *gpiopin, const unsigned int *delay_a_usec, const unsigned int *delay_b_usec)
{

for(;;) {
/* toggle pin high */
digitalWrite(*gpiopin, HIGH);
/* wait for delay_a_usec microseconds */
delayMicroseconds(*delay_a_usec);
/* toggle pin low */
digitalWrite(*gpiopin, LOW);
/* wait for delay_a_usec microseconds */
delayMicroseconds(*delay_a_usec);

/* toggle pin high */
digitalWrite(*gpiopin, HIGH);
delayMicroseconds(*delay_b_usec);
/* wait for delay_b_usec microseconds */

/* toggle pin low */
digitalWrite(*gpiopin, LOW);
delayMicroseconds(*delay_b_usec);
/* wait for delay_b_usec microseconds */
}

}

int main(int argc, char **argv)
{
/* gpio pin 17 on rpi3 is pin 0 in wiringpi */
const unsigned int gpiopin17 = 0x00;
/* 500000 microseconds */
const unsigned int delay_a_usec = 500000;
/* 225000  microseconds */
const unsigned int delay_b_usec = 225000;

/* no parameters allowed */
if(argc > 1) {
printf("error: argc > 1\n");
return EXIT_FAILURE;
}
/* setup wiring pi library. requires root */
if(wiringPiSetup() < 0) { 

printf("wiringPiSetup() error\n");
return EXIT_FAILURE;
}

/* set gpio pin to mode */
gpio_setup(&gpiopin17, OUTPUT);

/* toggle laser at two different frequencies */
gpio_toggle_pin(&gpiopin17, &delay_a_usec, &delay_b_usec);

return EXIT_SUCCESS;
}