Merged from git.drogon.net, SPI driver helpers, C++ wrappers, softPwm, piNes, gertboard, SPI

This commit is contained in:
Gordon Henderson
2012-08-28 18:37:54 +01:00
committed by Philip Howard
parent 21f0472265
commit ae40bdaf6a
22 changed files with 1708 additions and 279 deletions

122
wiringPi/gertboard.c Normal file
View File

@@ -0,0 +1,122 @@
/*
* gertboard.c:
* Access routines for the SPI devices on the Gertboard
* Copyright (c) 2012 Gordon Henderson
*
* The Gertboard has:
*
* An MCP3002 dual-channel A to D convertor connected
* to the SPI bus, selected by chip-select A, and:
*
* An MCP4802 dual-channel D to A convertor connected
* to the SPI bus, selected via chip-select B.
*
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include "wiringPiSPI.h"
#include "gertboard.h"
// The A-D convertor won't run at more than 1MHz @ 3.3v
#define SPI_ADC_SPEED 1000000
#define SPI_DAC_SPEED 1000000
#define SPI_A2D 0
#define SPI_D2A 1
/*
* gertboardAnalogWrite:
* Write an 8-bit data value to the MCP4802 Analog to digital
* convertor on the Gertboard.
*********************************************************************************
*/
void gertboardAnalogWrite (int chan, int value)
{
uint8_t spiData [2] ;
uint8_t chanBits, dataBits ;
if (chan == 0)
chanBits = 0x30 ;
else
chanBits = 0xB0 ;
chanBits |= ((value >> 4) & 0x0F) ;
dataBits = ((value << 4) & 0xF0) ;
spiData [0] = chanBits ;
spiData [1] = dataBits ;
wiringPiSPIDataRW (SPI_D2A, spiData, 2) ;
}
/*
* gertboardAnalogRead:
* Return the analog value of the given channel (0/1).
* The A/D is a 10-bit device
*********************************************************************************
*/
int gertboardAnalogRead (int chan)
{
uint8_t spiData [2] ;
uint8_t chanBits ;
if (chan == 0)
chanBits = 0b11010000 ;
else
chanBits = 0b11110000 ;
spiData [0] = chanBits ;
spiData [1] = 0 ;
wiringPiSPIDataRW (SPI_A2D, spiData, 2) ;
return ((spiData [0] << 7) | (spiData [1] >> 1)) & 0x3FF ;
}
/*
* gertboardSPISetup:
* Initialise the SPI bus, etc.
*********************************************************************************
*/
int gertboardSPISetup (void)
{
if (wiringPiSPISetup (SPI_A2D, SPI_ADC_SPEED) < 0)
return -1 ;
if (wiringPiSPISetup (SPI_D2A, SPI_DAC_SPEED) < 0)
return -1 ;
return 0 ;
}

39
wiringPi/gertboard.h Normal file
View File

@@ -0,0 +1,39 @@
/*
* gertboard.h:
* Access routines for the SPI devices on the Gertboard
* Copyright (c) 2012 Gordon Henderson
*
* The Gertboard has an MCP4802 dual-channel D to A convertor
* connected to the SPI bus, selected via chip-select B.
*
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
extern void gertboardAnalogWrite (int chan, int value) ;
extern int gertboardAnalogRead (int chan) ;
extern int gertboardSPISetup (void) ;
#ifdef __cplusplus
}
#endif

View File

@@ -33,5 +33,13 @@ extern void lcdPutchar (int fd, uint8_t data) ;
extern void lcdPuts (int fd, char *string) ;
extern void lcdPrintf (int fd, char *message, ...) ;
#ifdef __cplusplus
extern "C" {
#endif
extern int lcdInit (int rows, int cols, int bits, int rs, int strb,
int d0, int d1, int d2, int d3, int d4, int d5, int d6, int d7) ;
#ifdef __cplusplus
}
#endif

113
wiringPi/piNes.c Normal file
View File

@@ -0,0 +1,113 @@
/*
* piNes.c:
* Driver for the NES Joystick controller on the Raspberry Pi
* Copyright (c) 2012 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#include <wiringPi.h>
#include "piNes.h"
#define MAX_NES_JOYSTICKS 8
#define NES_RIGHT 0x01
#define NES_LEFT 0x02
#define NES_DOWN 0x04
#define NES_UP 0x08
#define NES_START 0x10
#define NES_SELECT 0x20
#define NES_B 0x40
#define NES_A 0x80
#define PULSE_TIME 25
// Data to store the pins for each controller
struct nesPinsStruct
{
unsigned int cPin, dPin, lPin ;
} ;
static struct nesPinsStruct nesPins [MAX_NES_JOYSTICKS] ;
static int joysticks = 0 ;
/*
* setupNesJoystick:
* Create a new NES joystick interface, program the pins, etc.
*********************************************************************************
*/
int setupNesJoystick (int dPin, int cPin, int lPin)
{
if (joysticks == MAX_NES_JOYSTICKS)
return -1 ;
nesPins [joysticks].dPin = dPin ;
nesPins [joysticks].cPin = cPin ;
nesPins [joysticks].lPin = lPin ;
digitalWrite (lPin, LOW) ;
digitalWrite (cPin, LOW) ;
pinMode (lPin, OUTPUT) ;
pinMode (cPin, OUTPUT) ;
pinMode (dPin, INPUT) ;
return joysticks++ ;
}
/*
* readNesJoystick:
* Do a single scan of the NES Joystick.
*********************************************************************************
*/
unsigned int readNesJoystick (int joystick)
{
unsigned int value = 0 ;
int i ;
struct nesPinsStruct *pins = &nesPins [joystick] ;
// Toggle Latch - which presents the first bit
digitalWrite (pins->lPin, HIGH) ; delayMicroseconds (PULSE_TIME) ;
digitalWrite (pins->lPin, LOW) ; delayMicroseconds (PULSE_TIME) ;
// Read first bit
value = digitalRead (pins->dPin) ;
// Now get the next 7 bits with the clock
for (i = 0 ; i < 7 ; ++i)
{
digitalWrite (pins->cPin, HIGH) ; delayMicroseconds (PULSE_TIME) ;
digitalWrite (pins->cPin, LOW) ; delayMicroseconds (PULSE_TIME) ;
value = (value << 1) | digitalRead (pins->dPin) ;
}
return value ^ 0xFF ;
}

45
wiringPi/piNes.h Normal file
View File

@@ -0,0 +1,45 @@
/*
* piNes.h:
* Driver for the NES Joystick controller on the Raspberry Pi
* Copyright (c) 2012 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#define MAX_NES_JOYSTICKS 8
#define NES_RIGHT 0x01
#define NES_LEFT 0x02
#define NES_DOWN 0x04
#define NES_UP 0x08
#define NES_START 0x10
#define NES_SELECT 0x20
#define NES_B 0x40
#define NES_A 0x80
#ifdef __cplusplus
extern "C" {
#endif
extern int setupNesJoystick (int dPin, int cPin, int lPin) ;
extern unsigned int readNesJoystick (int joystick) ;
#ifdef __cplusplus
}
#endif

130
wiringPi/softPwm.c Normal file
View File

@@ -0,0 +1,130 @@
/*
* softPwm.c:
* Provide 2 channels of software driven PWM.
* Copyright (c) 2012 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#include <stdio.h>
#include <pthread.h>
#include "wiringPi.h"
#include "softPwm.h"
#define MAX_PINS 64
// The PWM Frequency is derived from the "pulse time" below. Essentially,
// the frequency is a function of the range and this pulse time.
// The total period will be range * pulse time in uS, so a pulse time
// of 100 and a range of 100 gives a period of 100 * 100 = 10,000 uS
// which is a frequency of 100Hz.
//
// It's possible to get a higher frequency by lowering the pulse time,
// however CPU uage will skyrocket as wiringPi uses a hard-loop to time
// periods under 100uS - this is because the Linux timer calls are just
// accurate at all, and have an overhead.
//
// Another way to increase the frequency is to reduce the range - however
// that reduces the overall output accuracy...
#define PULSE_TIME 100
static int marks [MAX_PINS] ;
static int range [MAX_PINS] ;
int newPin = -1 ;
/*
* softPwmThread:
* Thread to do the actual PWM output
*********************************************************************************
*/
static PI_THREAD (softPwmThread)
{
int pin, mark, space ;
pin = newPin ;
newPin = -1 ;
piHiPri (50) ;
for (;;)
{
mark = marks [pin] ;
space = range [pin] - mark ;
if (mark != 0)
digitalWrite (pin, HIGH) ;
delayMicroseconds (mark * 100) ;
if (space != 0)
digitalWrite (pin, LOW) ;
delayMicroseconds (space * 100) ;
}
return NULL ;
}
/*
* softPwmWrite:
* Write a PWM value to the given pin
*********************************************************************************
*/
void softPwmWrite (int pin, int value)
{
pin &= 63 ;
/**/ if (value < 0)
value = 0 ;
else if (value > range [pin])
value = range [pin] ;
marks [pin] = value ;
}
/*
* softPwmCreate:
* Create a new PWM thread.
*********************************************************************************
*/
int softPwmCreate (int pin, int initialValue, int pwmRange)
{
int res ;
pinMode (pin, OUTPUT) ;
digitalWrite (pin, LOW) ;
marks [pin] = initialValue ;
range [pin] = pwmRange ;
newPin = pin ;
res = piThreadCreate (softPwmThread) ;
while (newPin != -1)
delay (1) ;
return res ;
}

34
wiringPi/softPwm.h Normal file
View File

@@ -0,0 +1,34 @@
/*
* softPwm.h:
* Provide 2 channels of software driven PWM.
* Copyright (c) 2012 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
extern int softPwmCreate (int pin, int value, int range) ;
extern void softPwmWrite (int pin, int value) ;
#ifdef __cplusplus
}
#endif

View File

@@ -71,12 +71,16 @@
// Function stubs
void (*pinMode) (int pin, int mode) ;
void (*pullUpDnControl) (int pin, int pud) ;
void (*digitalWrite) (int pin, int value) ;
void (*pwmWrite) (int pin, int value) ;
int (*digitalRead) (int pin) ;
int (*waitForInterrupt) (int pin, int mS) ;
void (*pinMode) (int pin, int mode) ;
void (*pullUpDnControl) (int pin, int pud) ;
void (*digitalWrite) (int pin, int value) ;
void (*pwmWrite) (int pin, int value) ;
void (*setPadDrive) (int group, int value) ;
int (*digitalRead) (int pin) ;
int (*waitForInterrupt) (int pin, int mS) ;
void (*delayMicroseconds) (unsigned int howLong) ;
void (*pwmSetMode) (int mode) ;
void (*pwmSetRange) (unsigned int range) ;
#ifndef TRUE
@@ -84,6 +88,11 @@ int (*waitForInterrupt) (int pin, int mS) ;
#define FALSE (1==2)
#endif
// BCM Magic
#define BCM_PASSWORD 0x5A000000
// Port function select bits
#define FSEL_INPT 0b000
@@ -100,10 +109,11 @@ int (*waitForInterrupt) (int pin, int mS) ;
// Take from Gert/Doms code. Some of this is not in the manual
// that I can find )-:
#define BCM2708_PERI_BASE 0x20000000
#define BCM2708_PERI_BASE 0x20000000
#define GPIO_PADS (BCM2708_PERI_BASE + 0x100000)
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000)
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000)
#define GPIO_TIMER (BCM2708_PERI_BASE + 0x00B000)
#define GPIO_PWM (BCM2708_PERI_BASE + 0x20C000)
#define PAGE_SIZE (4*1024)
@@ -137,12 +147,27 @@ int (*waitForInterrupt) (int pin, int mS) ;
#define PWM0_SERIAL 0x0002 // Run in serial mode
#define PWM0_ENABLE 0x0001 // Channel Enable
// Timer
#define TIMER_LOAD (0x400 >> 2)
#define TIMER_VALUE (0x404 >> 2)
#define TIMER_CONTROL (0x408 >> 2)
#define TIMER_IRQ_CLR (0x40C >> 2)
#define TIMER_IRQ_RAW (0x410 >> 2)
#define TIMER_IRQ_MASK (0x414 >> 2)
#define TIMER_RELOAD (0x418 >> 2)
#define TIMER_PRE_DIV (0x41C >> 2)
#define TIMER_COUNTER (0x420 >> 2)
// Locals to hold pointers to the hardware
static volatile uint32_t *gpio ;
static volatile uint32_t *pwm ;
static volatile uint32_t *clk ;
static volatile uint32_t *pads ;
static volatile uint32_t *timer ;
static volatile uint32_t *timerIrqRaw ;
// The BCM2835 has 54 GPIO pins.
// BCM2835 data sheet, Page 90 onwards.
@@ -273,6 +298,8 @@ static uint8_t gpioToFEN [] =
// gpioToPUDCLK
// (Word) offset to the Pull Up Down Clock regsiter
#define GPPUD 37
static uint8_t gpioToPUDCLK [] =
{
38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,
@@ -352,30 +379,42 @@ void pinModeGpio (int pin, int mode)
if (!pwmRunning)
{
*(pwm + PWM_CONTROL) = 0 ; // Stop PWM
delayMicroseconds (10) ;
// Gert/Doms Values
*(clk + PWMCLK_DIV) = 0x5A000000 | (32<<12) ; // set pwm div to 32 (19.2/3 = 600KHz)
*(clk + PWMCLK_CNTL) = 0x5A000011 ; // Source=osc and enable
digitalWrite (pin, LOW) ;
*(pwm + PWM_CONTROL) = 0 ; // Disable PWM
delayMicroseconds (10) ;
*(pwm + PWM0_RANGE) = 0x400 ;
delayMicroseconds (10) ;
*(pwm + PWM1_RANGE) = 0x400 ;
*(clk + PWMCLK_DIV) = BCM_PASSWORD | (32<<12) ; // set pwm div to 32 (19.2/32 = 600KHz)
*(clk + PWMCLK_CNTL) = BCM_PASSWORD | 0x11 ; // Source=osc and enable
delayMicroseconds (10) ;
*(pwm + PWM0_RANGE) = 0x400 ; delayMicroseconds (10) ;
*(pwm + PWM1_RANGE) = 0x400 ; delayMicroseconds (10) ;
// Enable PWMs
*(pwm + PWM0_DATA) = 512 ;
*(pwm + PWM1_DATA) = 512 ;
// Balanced mode (default)
*(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ;
pwmRunning = TRUE ;
}
}
// When we change mode of any pin, we remove the pull up/downs
// Or we used to... Hm. Commented out now because for some wieird reason,
// it seems to block subsequent attempts to set the pull up/downs and I've
// not quite gotten to the bottom of why this happens
// The down-side is that the pull up/downs are rememberd in the SoC between
// power cycles, so it's going to be a good idea to explicitly set them in
// any new code.
//
// pullUpDnControl (pin, PUD_OFF) ;
pullUpDnControl (pin, PUD_OFF) ;
}
void pinModeWPi (int pin, int mode)
@@ -389,6 +428,38 @@ void pinModeSys (int pin, int mode)
}
/*
* pwmControl:
* Allow the user to control some of the PWM functions
*********************************************************************************
*/
void pwmSetModeWPi (int mode)
{
if (mode == PWM_MODE_MS)
*(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE | PWM0_MS_MODE | PWM1_MS_MODE ;
else
*(pwm + PWM_CONTROL) = PWM0_ENABLE | PWM1_ENABLE ;
}
void pwmSetModeSys (int mode)
{
return ;
}
void pwmSetRangeWPi (unsigned int range)
{
*(pwm + PWM0_RANGE) = range ; delayMicroseconds (10) ;
*(pwm + PWM1_RANGE) = range ; delayMicroseconds (10) ;
}
void pwmSetRangeSys (unsigned int range)
{
return ;
}
#ifdef notYetReady
/*
* pinED01:
@@ -414,12 +485,12 @@ void pinEnableED01Pi (int pin)
void digitalWriteWPi (int pin, int value)
{
int gpioPin = pinToGpio [pin & 63] ;
pin = pinToGpio [pin & 63] ;
if (value == LOW)
*(gpio + gpioToGPCLR [gpioPin]) = 1 << gpioPin ;
*(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ;
else
*(gpio + gpioToGPSET [gpioPin]) = 1 << gpioPin ;
*(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ;
}
void digitalWriteGpio (int pin, int value)
@@ -427,9 +498,9 @@ void digitalWriteGpio (int pin, int value)
pin &= 63 ;
if (value == LOW)
*(gpio + gpioToGPCLR [pin]) = 1 << pin ;
*(gpio + gpioToGPCLR [pin]) = 1 << (pin & 31) ;
else
*(gpio + gpioToGPSET [pin]) = 1 << pin ;
*(gpio + gpioToGPSET [pin]) = 1 << (pin & 31) ;
}
void digitalWriteSys (int pin, int value)
@@ -452,28 +523,55 @@ void digitalWriteSys (int pin, int value)
*********************************************************************************
*/
void pwmWriteWPi (int pin, int value)
{
int port, gpioPin ;
gpioPin = pinToGpio [pin & 63] ;
port = gpioToPwmPort [gpioPin] ;
*(pwm + port) = value & 0x3FF ;
}
void pwmWriteGpio (int pin, int value)
{
int port, gpioPin ;
int port ;
gpioPin = pin & 63 ;
port = gpioToPwmPort [gpioPin] ;
pin = pin & 63 ;
port = gpioToPwmPort [pin] ;
*(pwm + port) = value & 0x3FF ;
*(pwm + port) = value ;
}
void pwmWriteWPi (int pin, int value)
{
pwmWriteGpio (pinToGpio [pin & 63], value) ;
}
void pwmWriteSys (int pin, int value)
{
return ;
}
void pwmWriteSys (int pin, int value)
/*
* setPadDrive:
* Set the PAD driver value
*********************************************************************************
*/
void setPadDriveWPi (int group, int value)
{
uint32_t wrVal ;
if ((group < 0) || (group > 2))
return ;
wrVal = BCM_PASSWORD | 0x18 | (value & 7) ;
*(pads + group + 11) = wrVal ;
#ifdef DEBUG_PADS
printf ("setPadDrive: Group: %d, value: %d (%08X)\n", group, value, wrVal) ;
printf ("Read : %08X\n", *(pads + group + 11)) ;
#endif
}
void setPadDriveGpio (int group, int value)
{
setPadDriveWPi (group, value) ;
}
void setPadDriveSys (int group, int value)
{
return ;
}
@@ -487,13 +585,9 @@ void pwmWriteSys (int pin, int value)
int digitalReadWPi (int pin)
{
int gpioPin ;
pin = pinToGpio [pin & 63] ;
pin &= 63 ;
gpioPin = pinToGpio [pin] ;
if ((*(gpio + gpioToGPLEV [gpioPin]) & (1 << gpioPin)) != 0)
if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0)
return HIGH ;
else
return LOW ;
@@ -503,7 +597,7 @@ int digitalReadGpio (int pin)
{
pin &= 63 ;
if ((*(gpio + gpioToGPLEV [pin]) & (1 << pin)) != 0)
if ((*(gpio + gpioToGPLEV [pin]) & (1 << (pin & 31))) != 0)
return HIGH ;
else
return LOW ;
@@ -533,30 +627,21 @@ int digitalReadSys (int pin)
*********************************************************************************
*/
void pullUpDnControlWPi (int pin, int pud)
{
pin = pinToGpio [pin & 63] ;
*(gpio + 37) = pud ;
delayMicroseconds (10) ;
*(gpio + gpioToPUDCLK [pin]) = 1 << pin ;
delayMicroseconds (10) ;
*(gpio + 37) = 0 ;
*(gpio + gpioToPUDCLK [pin]) = 0 ;
}
void pullUpDnControlGpio (int pin, int pud)
{
pin &= 63 ;
pud &= 3 ;
*(gpio + 37) = pud ;
delayMicroseconds (10) ;
*(gpio + gpioToPUDCLK [pin]) = 1 << pin ;
delayMicroseconds (10) ;
*(gpio + GPPUD) = pud ; delayMicroseconds (5) ;
*(gpio + gpioToPUDCLK [pin]) = 1 << (pin & 31) ; delayMicroseconds (5) ;
*(gpio + 37) = 0 ;
*(gpio + gpioToPUDCLK [pin]) = 0 ;
*(gpio + GPPUD) = 0 ; delayMicroseconds (5) ;
*(gpio + gpioToPUDCLK [pin]) = 0 ; delayMicroseconds (5) ;
}
void pullUpDnControlWPi (int pin, int pud)
{
pullUpDnControlGpio (pinToGpio [pin & 63], pud) ;
}
void pullUpDnControlSys (int pin, int pud)
@@ -615,6 +700,94 @@ int waitForInterruptGpio (int pin, int mS)
/*
* delay:
* Wait for some number of milli seconds
*********************************************************************************
*/
void delay (unsigned int howLong)
{
struct timespec sleeper, dummy ;
sleeper.tv_sec = (time_t)(howLong / 1000) ;
sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ;
nanosleep (&sleeper, &dummy) ;
}
/*
* delayMicroseconds:
* This is somewhat intersting. It seems that on the Pi, a single call
* to nanosleep takes some 80 to 130 microseconds anyway, so while
* obeying the standards (may take longer), it's not always what we
* want!
*
* So what I'll do now is if the delay is less than 100uS we'll do it
* in a hard loop, watching a built-in counter on the ARM chip. This is
* somewhat sub-optimal in that it uses 100% CPU, something not an issue
* in a microcontroller, but under a multi-tasking, multi-user OS, it's
* wastefull, however we've no real choice )-:
*********************************************************************************
*/
void delayMicrosecondsSys (unsigned int howLong)
{
struct timespec sleeper, dummy ;
sleeper.tv_sec = 0 ;
sleeper.tv_nsec = (long)(howLong * 1000) ;
nanosleep (&sleeper, &dummy) ;
}
void delayMicrosecondsHard (unsigned int howLong)
{
*(timer + TIMER_LOAD) = howLong ;
*(timer + TIMER_IRQ_CLR) = 0 ;
while (*timerIrqRaw == 0)
;
}
void delayMicrosecondsWPi (unsigned int howLong)
{
struct timespec sleeper, dummy ;
/**/ if (howLong == 0)
return ;
else if (howLong < 100)
delayMicrosecondsHard (howLong) ;
else
{
sleeper.tv_sec = 0 ;
sleeper.tv_nsec = (long)(howLong * 1000) ;
nanosleep (&sleeper, &dummy) ;
}
}
/*
* millis:
* Return a number of milliseconds as an unsigned int.
*********************************************************************************
*/
unsigned int millis (void)
{
struct timeval tv ;
unsigned long long t1 ;
gettimeofday (&tv, NULL) ;
t1 = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ;
return (uint32_t)(t1 - epoch) ;
}
/*
* wiringPiSetup:
* Must be called once at the start of your program execution.
@@ -627,20 +800,19 @@ int waitForInterruptGpio (int pin, int mS)
int wiringPiSetup (void)
{
int fd ;
uint8_t *gpioMem, *pwmMem, *clkMem ;
uint8_t *gpioMem, *pwmMem, *clkMem, *padsMem, *timerMem ;
struct timeval tv ;
#ifdef DEBUG_PADS
uint8_t *gpioMem, *padsMem, *pwmMem, *clkMem ;
uint32_t *pads ;
#endif
pinMode = pinModeWPi ;
pullUpDnControl = pullUpDnControlWPi ;
digitalWrite = digitalWriteWPi ;
pwmWrite = pwmWriteWPi ;
digitalRead = digitalReadWPi ;
waitForInterrupt = waitForInterruptWPi ;
pinMode = pinModeWPi ;
pullUpDnControl = pullUpDnControlWPi ;
digitalWrite = digitalWriteWPi ;
pwmWrite = pwmWriteWPi ;
setPadDrive = setPadDriveWPi ;
digitalRead = digitalReadWPi ;
waitForInterrupt = waitForInterruptWPi ;
delayMicroseconds = delayMicrosecondsWPi ;
pwmSetMode = pwmSetModeWPi ;
pwmSetRange = pwmSetRangeWPi ;
// Open the master /dev/memory device
@@ -711,7 +883,8 @@ int wiringPiSetup (void)
return -1 ;
}
#ifdef DEBUG_PADS
// The drive pads
if ((padsMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
{
fprintf (stderr, "wiringPiSetup: padsMem malloc failed: %s\n", strerror (errno)) ;
@@ -728,14 +901,41 @@ int wiringPiSetup (void)
fprintf (stderr, "wiringPiSetup: mmap failed (pads): %s\n", strerror (errno)) ;
return -1 ;
}
printf ("Checking pads @ 0x%08X\n", (unsigned int)pads) ;
printf ("%08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ;
// *(pads + 11) = 0x1F ;
printf ("%08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ;
#ifdef DEBUG_PADS
printf ("Checking pads @ 0x%08X\n", (unsigned int)pads) ;
printf (" -> %08X %08X %08X\n", *(pads + 11), *(pads + 12), *(pads + 13)) ;
#endif
// The system timer
if ((timerMem = malloc (BLOCK_SIZE + (PAGE_SIZE-1))) == NULL)
{
fprintf (stderr, "wiringPiSetup: timerMem malloc failed: %s\n", strerror (errno)) ;
return -1 ;
}
if (((uint32_t)timerMem % PAGE_SIZE) != 0)
timerMem += PAGE_SIZE - ((uint32_t)timerMem % PAGE_SIZE) ;
timer = (uint32_t *)mmap(timerMem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, fd, GPIO_TIMER) ;
if ((int32_t)timer < 0)
{
fprintf (stderr, "wiringPiSetup: mmap failed (timer): %s\n", strerror (errno)) ;
return -1 ;
}
// Set the timer to free-running, 1MHz.
// 0xF9 is 249, the timer divide is base clock / (divide+1)
// so base clock is 250MHz / 250 = 1MHz.
*(timer + TIMER_CONTROL) = 0x0000280 ;
*(timer + TIMER_PRE_DIV) = 0x00000F9 ;
timerIrqRaw = timer + TIMER_IRQ_RAW ;
// Initialise our epoch for millis()
gettimeofday (&tv, NULL) ;
epoch = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ;
@@ -759,12 +959,16 @@ int wiringPiSetupGpio (void)
if (x != 0)
return x ;
pinMode = pinModeGpio ;
pullUpDnControl = pullUpDnControlGpio ;
digitalWrite = digitalWriteGpio ;
pwmWrite = pwmWriteGpio ;
digitalRead = digitalReadGpio ;
waitForInterrupt = waitForInterruptGpio ;
pinMode = pinModeGpio ;
pullUpDnControl = pullUpDnControlGpio ;
digitalWrite = digitalWriteGpio ;
pwmWrite = pwmWriteGpio ;
setPadDrive = setPadDriveGpio ;
digitalRead = digitalReadGpio ;
waitForInterrupt = waitForInterruptGpio ;
delayMicroseconds = delayMicrosecondsWPi ; // Same
pwmSetMode = pwmSetModeWPi ;
pwmSetRange = pwmSetRangeWPi ;
return 0 ;
}
@@ -785,12 +989,17 @@ int wiringPiSetupSys (void)
struct timeval tv ;
char fName [128] ;
pinMode = pinModeSys ;
pullUpDnControl = pullUpDnControlSys ;
digitalWrite = digitalWriteSys ;
pwmWrite = pwmWriteSys ;
digitalRead = digitalReadSys ;
waitForInterrupt = waitForInterruptSys ;
pinMode = pinModeSys ;
pullUpDnControl = pullUpDnControlSys ;
digitalWrite = digitalWriteSys ;
pwmWrite = pwmWriteSys ;
setPadDrive = setPadDriveSys ;
digitalRead = digitalReadSys ;
waitForInterrupt = waitForInterruptSys ;
delayMicroseconds = delayMicrosecondsSys ;
pwmSetMode = pwmSetModeSys ;
pwmSetRange = pwmSetRangeSys ;
// Open and scan the directory, looking for exported GPIOs, and pre-open
// the 'value' interface to speed things up for later
@@ -808,51 +1017,3 @@ int wiringPiSetupSys (void)
return 0 ;
}
/*
* delay: delayMicroseconds
* Wait for some number of milli/micro seconds
*********************************************************************************
*/
void delay (unsigned int howLong)
{
struct timespec sleeper, dummy ;
sleeper.tv_sec = (time_t)(howLong / 1000) ;
sleeper.tv_nsec = (long)(howLong % 1000) * 1000000 ;
nanosleep (&sleeper, &dummy) ;
}
void delayMicroseconds (unsigned int howLong)
{
struct timespec sleeper, dummy ;
sleeper.tv_sec = 0 ;
sleeper.tv_nsec = (long)(howLong * 1000) ;
nanosleep (&sleeper, &dummy) ;
}
/*
* millis:
* Return a number of milliseconds as an unsigned int.
*********************************************************************************
*/
unsigned int millis (void)
{
struct timeval tv ;
unsigned long long t1 ;
gettimeofday (&tv, NULL) ;
t1 = (tv.tv_sec * 1000000 + tv.tv_usec) / 1000 ;
return (uint32_t)(t1 - epoch) ;
}

View File

@@ -41,6 +41,12 @@
#define PUD_DOWN 1
#define PUD_UP 2
// PWM
#define PWM_MODE_MS 0
#define PWM_MODE_BAL 1
// Function prototypes
// c++ wrappers thanks to a commend by Nick Lott
// (and others on the Raspberry Pi forums)
@@ -58,11 +64,15 @@ extern int wiringPiSetupPiFace (void) ;
extern int wiringPiSetupPiFaceForGpioProg (void) ; // Don't use this - for gpio program only
extern void (*pinMode) (int pin, int mode) ;
extern void (*pullUpDnControl) (int pin, int pud) ;
extern void (*digitalWrite) (int pin, int value) ;
extern void (*pwmWrite) (int pin, int value) ;
extern int (*digitalRead) (int pin) ;
extern void (*pinMode) (int pin, int mode) ;
extern void (*pullUpDnControl) (int pin, int pud) ;
extern void (*digitalWrite) (int pin, int value) ;
extern void (*pwmWrite) (int pin, int value) ;
extern void (*setPadDrive) (int group, int value) ;
extern int (*digitalRead) (int pin) ;
extern void (*delayMicroseconds) (unsigned int howLong) ;
extern void (*pwmSetMode) (int mode) ;
extern void (*pwmSetRange) (unsigned int range) ;
// Interrupts
@@ -84,7 +94,6 @@ extern int piHiPri (int pri) ;
// Extras from arduino land
extern void delay (unsigned int howLong) ;
extern void delayMicroseconds (unsigned int howLong) ;
extern unsigned int millis (void) ;
#ifdef __cplusplus

117
wiringPi/wiringPiSPI.c Normal file
View File

@@ -0,0 +1,117 @@
/*
* wiringPiSPI.c:
* Simplified SPI access routines
* Copyright (c) 2012 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#include <stdint.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h>
#include "wiringPiSPI.h"
// The SPI bus parameters
// Variables as they need to be passed as pointers later on
static char *spiDev0 = "/dev/spidev0.0" ;
static char *spiDev1 = "/dev/spidev0.1" ;
static uint8_t spiMode = 0 ;
static uint8_t spiBPW = 8 ;
static uint16_t spiDelay = 0;
static uint32_t spiSpeeds [2] ;
static int spiFds [2] ;
/*
* wiringPiSPIGetFd:
* Return the file-descriptor for the given channel
*********************************************************************************
*/
int wiringPiSPIGetFd (int channel)
{
return spiFds [channel &1] ;
}
/*
* wiringPiSPIDataRW:
* Write and Read a block of data over the SPI bus.
* Note the data ia being read into the transmit buffer, so will
* overwrite it!
* This is also a full-duplex operation.
*********************************************************************************
*/
int wiringPiSPIDataRW (int channel, unsigned char *data, int len)
{
struct spi_ioc_transfer spi ;
channel &= 1 ;
spi.tx_buf = (unsigned long)data ;
spi.rx_buf = (unsigned long)data ;
spi.len = len ;
spi.delay_usecs = spiDelay ;
spi.speed_hz = spiSpeeds [channel] ;
spi.bits_per_word = spiBPW ;
return ioctl (spiFds [channel], SPI_IOC_MESSAGE(1), &spi) ;
}
/*
* wiringPiSPISetup:
* Open the SPI device, and set it up, etc.
*********************************************************************************
*/
int wiringPiSPISetup (int channel, int speed)
{
int fd ;
channel &= 1 ;
if ((fd = open (channel == 0 ? spiDev0 : spiDev1, O_RDWR)) < 0)
return -1 ;
spiSpeeds [channel] = speed ;
spiFds [channel] = fd ;
// Set SPI parameters.
// Why are we reading it afterwriting it? I've no idea, but for now I'm blindly
// copying example code I've seen online...
if (ioctl (fd, SPI_IOC_WR_MODE, &spiMode) < 0) return -1 ;
if (ioctl (fd, SPI_IOC_RD_MODE, &spiMode) < 0) return -1 ;
if (ioctl (fd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0) return -1 ;
if (ioctl (fd, SPI_IOC_RD_BITS_PER_WORD, &spiBPW) < 0) return -1 ;
if (ioctl (fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) return -1 ;
if (ioctl (fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) return -1 ;
return fd ;
}

35
wiringPi/wiringPiSPI.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* wiringPiSPI.h:
* Simplified SPI access routines
* Copyright (c) 2012 Gordon Henderson
***********************************************************************
* This file is part of wiringPi:
* https://projects.drogon.net/raspberry-pi/wiringpi/
*
* wiringPi is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* wiringPi 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with wiringPi.
* If not, see <http://www.gnu.org/licenses/>.
***********************************************************************
*/
#ifdef __cplusplus
extern "C" {
#endif
int wiringPiSPIGetFd (int channel) ;
int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ;
int wiringPiSPISetup (int channel, int speed) ;
#ifdef __cplusplus
}
#endif

View File

@@ -20,8 +20,6 @@
***********************************************************************
*/
#undef DEBUG
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
@@ -49,10 +47,6 @@ int serialOpen (char *device, int baud)
speed_t myBaud ;
int status, fd ;
#ifdef DEBUG
printf ("openSerialPort: <%s> baud: $d\n", device, baud) ;
#endif
switch (baud)
{
case 50: myBaud = B50 ; break ;
@@ -86,22 +80,22 @@ int serialOpen (char *device, int baud)
tcgetattr (fd, &options) ;
cfmakeraw (&options) ;
cfsetispeed (&options, myBaud) ;
cfsetospeed (&options, myBaud) ;
cfmakeraw (&options) ;
cfsetispeed (&options, myBaud) ;
cfsetospeed (&options, myBaud) ;
options.c_cflag |= (CLOCAL | CREAD) ;
options.c_cflag &= ~PARENB ;
options.c_cflag &= ~CSTOPB ;
options.c_cflag &= ~CSIZE ;
options.c_cflag |= CS8 ;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
options.c_oflag &= ~OPOST ;
options.c_cflag |= (CLOCAL | CREAD) ;
options.c_cflag &= ~PARENB ;
options.c_cflag &= ~CSTOPB ;
options.c_cflag &= ~CSIZE ;
options.c_cflag |= CS8 ;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
options.c_oflag &= ~OPOST ;
options.c_cc [VMIN] = 0 ;
options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds)
options.c_cc [VMIN] = 0 ;
options.c_cc [VTIME] = 100 ; // Ten seconds (100 deciseconds)
tcsetattr (fd, TCSANOW, &options) ;
tcsetattr (fd, TCSANOW | TCSAFLUSH, &options) ;
ioctl (fd, TIOCMGET, &status);
@@ -116,6 +110,18 @@ int serialOpen (char *device, int baud)
}
/*
* serialFlush:
* Flush the serial buffers (both tx & rx)
*********************************************************************************
*/
void serialFlush (int fd)
{
tcflush (fd, TCIOFLUSH) ;
}
/*
* serialClose:
* Release the serial port

View File

@@ -26,6 +26,7 @@ extern "C" {
extern int serialOpen (char *device, int baud) ;
extern void serialClose (int fd) ;
extern void serialFlush (int fd) ;
extern void serialPutchar (int fd, unsigned char c) ;
extern void serialPuts (int fd, char *s) ;
extern void serialPrintf (int fd, char *message, ...) ;