Added Software SPI

Added Software SPI:
bbSPIopen
bbSPIclose
bbSPIxfer
Some documentation is not finished yet.
This commit is contained in:
BjoernSch 2016-08-06 12:18:17 +02:00
parent 5fcd079681
commit c91dbb5220
4 changed files with 524 additions and 18 deletions

View File

@ -49,6 +49,10 @@ cmdInfo_t cmdInfo[]=
{PI_CMD_BI2CO, "BI2CO", 131, 0}, // bbI2COpen {PI_CMD_BI2CO, "BI2CO", 131, 0}, // bbI2COpen
{PI_CMD_BI2CZ, "BI2CZ", 193, 6}, // bbI2CZip {PI_CMD_BI2CZ, "BI2CZ", 193, 6}, // bbI2CZip
{PI_CMD_BSPIC, "BSPIC", 112, 0}, // bbSPIClose
{PI_CMD_BSPIO, "BSPIO", 134, 0}, // bbSPIOpen
{PI_CMD_BSPIX, "BSPIX", 193, 6}, // bbSPIXfer
{PI_CMD_BR1, "BR1", 101, 3}, // gpioRead_Bits_0_31 {PI_CMD_BR1, "BR1", 101, 3}, // gpioRead_Bits_0_31
{PI_CMD_BR2, "BR2", 101, 3}, // gpioRead_Bits_32_53 {PI_CMD_BR2, "BR2", 101, 3}, // gpioRead_Bits_32_53
@ -256,6 +260,11 @@ BC2 bits Clear GPIO in bank 2\n\
BI2CC sda Close bit bang I2C\n\ BI2CC sda Close bit bang I2C\n\
BI2CO sda scl baud | Open bit bang I2C\n\ BI2CO sda scl baud | Open bit bang I2C\n\
BI2CZ sda ... I2C bit bang multiple transactions\n\ BI2CZ sda ... I2C bit bang multiple transactions\n\
\n\
BSPIC cs Close bit bang SPI\n\
BSPIO cs miso mosi sclk baud flag | Open bit bang SPI\n\
BSPIX cs ... SPI bit bang transfer\n\
\n\
BR1 Read bank 1 GPIO\n\ BR1 Read bank 1 GPIO\n\
BR2 Read bank 2 GPIO\n\ BR2 Read bank 2 GPIO\n\
BS1 bits Set GPIO in bank 1\n\ BS1 bits Set GPIO in bank 1\n\
@ -529,6 +538,8 @@ static errInfo_t errInfo[]=
{PI_FILE_IS_A_DIR , "file is a directory"}, {PI_FILE_IS_A_DIR , "file is a directory"},
{PI_BAD_SHELL_STATUS , "bad shell return status"}, {PI_BAD_SHELL_STATUS , "bad shell return status"},
{PI_BAD_SCRIPT_NAME , "bad script name"}, {PI_BAD_SCRIPT_NAME , "bad script name"},
{PI_BAD_SPI_BAUD , "bad SPI baud rate, not 50-500k"},
{PI_NOT_SPI_GPIO , "no bit bang SPI in progress on GPIO"},
}; };
@ -599,8 +610,8 @@ int cmdParse(
char *p8; char *p8;
int32_t *p32; int32_t *p32;
char c; char c;
uint32_t tp1=0, tp2=0, tp3=0; uint32_t tp1=0, tp2=0, tp3=0, tp4=0, tp5=0;
int8_t to1, to2, to3; int8_t to1, to2, to3, to4, to5;
int eaten; int eaten;
/* Check that ext is big enough for the largest message. */ /* Check that ext is big enough for the largest message. */
@ -653,7 +664,7 @@ int cmdParse(
case 112: /* BI2CC FC GDC GPW I2CC I2CRB case 112: /* BI2CC FC GDC GPW I2CC I2CRB
MG MICS MILS MODEG NC NP PADG PFG PRG MG MICS MILS MODEG NC NP PADG PFG PRG
PROCD PROCP PROCS PRRG R READ SLRC SPIC PROCD PROCP PROCS PRRG R READ SLRC SPIC
WVDEL WVSC WVSM WVSP WVTX WVTXR WVDEL WVSC WVSM WVSP WVTX WVTXR BSPIC
One positive parameter. One positive parameter.
*/ */
@ -914,6 +925,36 @@ int cmdParse(
break; break;
case 134: /* BSPIO
Six parameters. First to Fifth positive.
Sixth may be negative when interpreted as an int.
*/
ctl->eaten += getNum(buf+ctl->eaten, &p[1], &ctl->opt[1]);
ctl->eaten += getNum(buf+ctl->eaten, &tp1, &to1);
ctl->eaten += getNum(buf+ctl->eaten, &tp2, &to2);
ctl->eaten += getNum(buf+ctl->eaten, &tp3, &to3);
ctl->eaten += getNum(buf+ctl->eaten, &tp4, &to4);
ctl->eaten += getNum(buf+ctl->eaten, &tp5, &to5);
if ((ctl->opt[1] > 0) && ((int)p[1] >= 0) &&
(to1 == CMD_NUMERIC) && ((int)tp1 >= 0) &&
(to2 == CMD_NUMERIC) && ((int)tp2 >= 0) &&
(to3 == CMD_NUMERIC) && ((int)tp3 >= 0) &&
(to4 == CMD_NUMERIC) && ((int)tp4 >= 0) &&
(to5 == CMD_NUMERIC))
{
p[3] = 5 * 4;
memcpy(ext, &tp1, 4);
memcpy(ext, &tp2, 4);
memcpy(ext, &tp3, 4);
memcpy(ext, &tp4, 4);
memcpy(ext, &tp5, 4);
valid = 1;
}
break;
case 191: /* PROCR case 191: /* PROCR
One to 11 parameters, first positive, One to 11 parameters, first positive,
@ -971,6 +1012,7 @@ int cmdParse(
break; break;
case 193: /* BI2CZ FW I2CWD I2CZ SERW SPIW SPIX case 193: /* BI2CZ FW I2CWD I2CZ SERW SPIW SPIX
BSPIX
Two or more parameters, first >=0, rest 0-255. Two or more parameters, first >=0, rest 0-255.
*/ */

320
pigpio.c
View File

@ -752,6 +752,10 @@ Assumes two counters per block. Each counter 4 * 16 (16^4=65536)
#define PI_WFRX_SERIAL 1 #define PI_WFRX_SERIAL 1
#define PI_WFRX_I2C 2 #define PI_WFRX_I2C 2
#define PI_WFRX_I2C_CLK 3 #define PI_WFRX_I2C_CLK 3
#define PI_WFRX_SPI_MISO 4
#define PI_WFRX_SPI_MOSI 5
#define PI_WFRX_SPI_CS 6
#define PI_WFRX_SPI_SCLK 7
#define PI_WF_MICROS 1 #define PI_WF_MICROS 1
@ -846,6 +850,8 @@ Assumes two counters per block. Each counter 4 * 16 (16^4=65536)
#define PI_SPI_FLAGS_GET_RESVD(x) (((x)>>5)&7) #define PI_SPI_FLAGS_GET_RESVD(x) (((x)>>5)&7)
#define PI_SPI_FLAGS_GET_CSPOLS(x) (((x)>>2)&7) #define PI_SPI_FLAGS_GET_CSPOLS(x) (((x)>>2)&7)
#define PI_SPI_FLAGS_GET_MODE(x) ((x)&3) #define PI_SPI_FLAGS_GET_MODE(x) ((x)&3)
#define PI_SPI_FLAGS_GET_CPHA(x) ((x)&1)
#define PI_SPI_FLAGS_GET_CPOL(x) ((x)&2)
#define PI_STARTING 0 #define PI_STARTING 0
#define PI_RUNNING 1 #define PI_RUNNING 1
@ -1095,6 +1101,21 @@ typedef struct
int started; int started;
} wfRxI2C_t; } wfRxI2C_t;
typedef struct
{
int MISO;
int MOSI;
int CS;
int SCLK;
int delay;
int spiFlags;
int MISOMode;
int MOSIMode;
int CSMode;
int SCLKMode;
int started;
} wfRxSPI_t;
typedef struct typedef struct
{ {
int mode; int mode;
@ -1104,6 +1125,7 @@ typedef struct
{ {
wfRxSerial_t s; wfRxSerial_t s;
wfRxI2C_t I; wfRxI2C_t I;
wfRxSPI_t S;
}; };
} wfRx_t; } wfRx_t;
@ -1757,10 +1779,9 @@ static int myDoCommand(uint32_t *p, unsigned bufSize, char *buf)
{ {
int res, i, j; int res, i, j;
uint32_t mask; uint32_t mask;
uint32_t tmp1, tmp2, tmp3; uint32_t tmp1, tmp2, tmp3, tmp4, tmp5;
gpioPulse_t *pulse; gpioPulse_t *pulse;
int masked; int masked;
res = 0; res = 0;
switch (p[0]) switch (p[0])
@ -1793,7 +1814,9 @@ static int myDoCommand(uint32_t *p, unsigned bufSize, char *buf)
} }
break; break;
case PI_CMD_BI2CC: res = bbI2CClose(p[1]); break; case PI_CMD_BI2CC:
res = bbI2CClose(p[1]);
break;
case PI_CMD_BI2CO: case PI_CMD_BI2CO:
memcpy(&p[4], buf, 4); memcpy(&p[4], buf, 4);
@ -1810,6 +1833,25 @@ static int myDoCommand(uint32_t *p, unsigned bufSize, char *buf)
} }
break; break;
case PI_CMD_BSPIO:
memcpy(&tmp1, buf, 4); // MISO
memcpy(&tmp2, buf+4, 4); // MOSI
memcpy(&tmp3, buf+8, 4); // SCLK
memcpy(&tmp4, buf+12, 4);// baud
memcpy(&tmp5, buf+16, 4);// flags
res = bbSPIOpen(p[1], tmp1, tmp2, tmp3, tmp4, tmp5);
break;
case PI_CMD_BSPIC:
res = bbSPIClose(p[1]);
break;
case PI_CMD_BSPIX:
if (p[3] > bufSize) p[3] = bufSize;
res = bbSPIXfer(p[1], buf, buf, p[3]);
break;
case PI_CMD_BR1: res = gpioRead_Bits_0_31(); break; case PI_CMD_BR1: res = gpioRead_Bits_0_31(); break;
case PI_CMD_BR2: res = gpioRead_Bits_32_53(); break; case PI_CMD_BR2: res = gpioRead_Bits_32_53(); break;
@ -1995,8 +2037,6 @@ static int myDoCommand(uint32_t *p, unsigned bufSize, char *buf)
} }
break; break;
case PI_CMD_MICS: case PI_CMD_MICS:
if (p[1] <= PI_MAX_MICS_DELAY) myGpioDelay(p[1]); if (p[1] <= PI_MAX_MICS_DELAY) myGpioDelay(p[1]);
else res = PI_BAD_MICS_DELAY; else res = PI_BAD_MICS_DELAY;
@ -2144,8 +2184,9 @@ static int myDoCommand(uint32_t *p, unsigned bufSize, char *buf)
case PI_CMD_SLRI: res = gpioSerialReadInvert(p[1], p[2]); break; case PI_CMD_SLRI: res = gpioSerialReadInvert(p[1], p[2]); break;
case PI_CMD_SPIC:
case PI_CMD_SPIC: res = spiClose(p[1]); break; res = spiClose(p[1]);
break;
case PI_CMD_SPIO: case PI_CMD_SPIO:
memcpy(&p[4], buf, 4); memcpy(&p[4], buf, 4);
@ -6651,6 +6692,7 @@ static void *pthSocketThreadHandler(void *fdC)
case PI_CMD_SLR: case PI_CMD_SLR:
case PI_CMD_SPIX: case PI_CMD_SPIX:
case PI_CMD_SPIR: case PI_CMD_SPIR:
case PI_CMD_BSPIX:
if (((int)p[3]) > 0) if (((int)p[3]) > 0)
{ {
@ -9744,6 +9786,26 @@ static int read_SDA(wfRx_t *w)
return gpioRead(w->I.SDA); return gpioRead(w->I.SDA);
} }
static void set_CS(wfRx_t *w)
{
myGpioWrite(w->S.CS, PI_SPI_FLAGS_GET_CSPOLS(w->S.spiFlags));
}
static void clear_CS(wfRx_t *w)
{
myGpioWrite(w->S.CS, !PI_SPI_FLAGS_GET_CSPOLS(w->S.spiFlags));
}
static void set_SCLK(wfRx_t *w)
{
myGpioWrite(w->S.SCLK, !PI_SPI_FLAGS_GET_CPOL(w->S.spiFlags));
}
static void clear_SCLK(wfRx_t *w)
{
myGpioWrite(w->S.SCLK, PI_SPI_FLAGS_GET_CPOL(w->S.spiFlags));
}
static void set_SDA(wfRx_t *w) static void set_SDA(wfRx_t *w)
{ {
myGpioSetMode(w->I.SDA, PI_INPUT); myGpioSetMode(w->I.SDA, PI_INPUT);
@ -9766,6 +9828,11 @@ static void I2C_delay(wfRx_t *w)
myGpioDelay(w->I.delay); myGpioDelay(w->I.delay);
} }
static void SPI_delay(wfRx_t *w)
{
myGpioDelay(w->S.delay);
}
static void I2C_clock_stretch(wfRx_t *w) static void I2C_clock_stretch(wfRx_t *w)
{ {
uint32_t now, max_stretch=10000; uint32_t now, max_stretch=10000;
@ -9775,6 +9842,30 @@ static void I2C_clock_stretch(wfRx_t *w)
while ((gpioRead(w->I.SCL) == 0) && ((gpioTick()-now) < max_stretch)); while ((gpioRead(w->I.SCL) == 0) && ((gpioTick()-now) < max_stretch));
} }
static void bbSPIStart(wfRx_t *w)
{
if (w->S.started)
{
clear_SCLK(w);
clear_CS(w);
SPI_delay(w);
}
clear_SCLK(w);
set_CS(w);
w->S.started = 1;
}
static void bbSPIStop(wfRx_t *w)
{
clear_CS(w);
clear_SCLK(w);
SPI_delay(w);
w->S.started = 0;
}
static void I2CStart(wfRx_t *w) static void I2CStart(wfRx_t *w)
{ {
if (w->I.started) if (w->I.started)
@ -9859,6 +9950,71 @@ static uint8_t I2CGetByte(wfRx_t *w, int nack)
return byte; return byte;
} }
static uint8_t bbSPIXferByte(wfRx_t *w, char txByte)
{
uint8_t bit, rxByte=0;
if (PI_SPI_FLAGS_GET_CPHA(w->S.spiFlags))
{
for (bit=0; bit<8; bit++)
{
if (PI_SPI_FLAGS_GET_TX_LSB(w->S.spiFlags))
{
myGpioWrite(w->S.MOSI, txByte & 0x01);
txByte >>= 1;
}
else
{
myGpioWrite(w->S.MOSI, txByte & 0x80);
txByte <<= 1;
}
set_SCLK(w);
SPI_delay(w);
if (PI_SPI_FLAGS_GET_RX_LSB(w->S.spiFlags))
{
rxByte = (rxByte >> 1) | myGpioRead(w->S.MISO) << 7;
}
else
{
rxByte = (rxByte << 1) | myGpioRead(w->S.MISO);
}
clear_SCLK(w);
SPI_delay(w);
}
}
else
{
for (bit=0; bit<8; bit++)
{
if (PI_SPI_FLAGS_GET_TX_LSB(w->S.spiFlags))
{
myGpioWrite(w->S.MOSI, txByte & 0x01);
txByte >>= 1;
}
else
{
myGpioWrite(w->S.MOSI, txByte & 0x80);
txByte <<= 1;
}
if (PI_SPI_FLAGS_GET_RX_LSB(w->S.spiFlags))
{
rxByte = (rxByte >> 1) | myGpioRead(w->S.MISO) << 7;
}
else
{
rxByte = (rxByte << 1) | myGpioRead(w->S.MISO);
}
set_SCLK(w);
SPI_delay(w);
clear_SCLK(w);
SPI_delay(w);
}
}
return rxByte;
}
int bbI2COpen(unsigned SDA, unsigned SCL, unsigned baud) int bbI2COpen(unsigned SDA, unsigned SCL, unsigned baud)
{ {
DBG(DBG_USER, "SDA=%d SCL=%d baud=%d", SDA, SCL, baud); DBG(DBG_USER, "SDA=%d SCL=%d baud=%d", SDA, SCL, baud);
@ -9888,7 +10044,7 @@ int bbI2COpen(unsigned SDA, unsigned SCL, unsigned baud)
wfRx[SDA].I.started = 0; wfRx[SDA].I.started = 0;
wfRx[SDA].I.SDA = SDA; wfRx[SDA].I.SDA = SDA;
wfRx[SDA].I.SCL = SCL; wfRx[SDA].I.SCL = SCL;
wfRx[SDA].I.delay = 500000 / baud; wfRx[SDA].I.delay = (500000 / baud) - 1;
wfRx[SDA].I.SDAMode = gpioGetMode(SDA); wfRx[SDA].I.SDAMode = gpioGetMode(SDA);
wfRx[SDA].I.SCLMode = gpioGetMode(SCL); wfRx[SDA].I.SCLMode = gpioGetMode(SCL);
@ -9901,6 +10057,73 @@ int bbI2COpen(unsigned SDA, unsigned SCL, unsigned baud)
return 0; return 0;
} }
int bbSPIOpen(unsigned CS, unsigned MISO, unsigned MOSI, unsigned SCLK, unsigned baud, unsigned spiFlags)
{
DBG(DBG_USER, "MISO=%d MOSI=%d CS=%d SCLK=%d baud=%d", MISO, MOSI, CS, SCLK, baud);
CHECK_INITED;
if (CS > PI_MAX_USER_GPIO)
SOFT_ERROR(PI_BAD_USER_GPIO, "bad CS (%d)", CS);
if (MISO > PI_MAX_USER_GPIO)
SOFT_ERROR(PI_BAD_USER_GPIO, "bad MISO (%d)", MISO);
if (MOSI > PI_MAX_USER_GPIO)
SOFT_ERROR(PI_BAD_USER_GPIO, "bad MOSI (%d)", MOSI);
if (SCLK > PI_MAX_USER_GPIO)
SOFT_ERROR(PI_BAD_USER_GPIO, "bad SCLK (%d)", SCLK);
if ((baud < PI_BB_SPI_MIN_BAUD) || (baud > PI_BB_SPI_MAX_BAUD))
SOFT_ERROR(PI_BAD_SPI_BAUD,
"CS %d, bad baud rate (%d)", CS, baud);
if (wfRx[CS].mode != PI_WFRX_NONE)
SOFT_ERROR(PI_GPIO_IN_USE, "gpio %d is already being used, mode %d", CS, wfRx[CS].mode);
if (!((wfRx[MISO].mode == PI_WFRX_NONE) || (wfRx[MISO].mode == PI_WFRX_SPI_MISO)) || (MISO == CS))
SOFT_ERROR(PI_GPIO_IN_USE, "gpio %d is already being used, mode %d", MISO, wfRx[MISO].mode);
if (!((wfRx[MOSI].mode == PI_WFRX_NONE) || (wfRx[MOSI].mode == PI_WFRX_SPI_MOSI)) || (MOSI == CS) || (MOSI == MISO))
SOFT_ERROR(PI_GPIO_IN_USE, "gpio %d is already being used, mode %d", MOSI, wfRx[MOSI].mode);
if (!((wfRx[SCLK].mode == PI_WFRX_NONE) || (wfRx[SCLK].mode == PI_WFRX_SPI_SCLK)) || (SCLK == CS) || (SCLK == MISO) || (SCLK == MOSI))
SOFT_ERROR(PI_GPIO_IN_USE, "gpio %d is already being used, mode %d", SCLK, wfRx[SCLK].mode);
wfRx[MISO].gpio = MISO;
wfRx[MISO].mode = PI_WFRX_SPI_MISO;
wfRx[MOSI].gpio = MOSI;
wfRx[MOSI].mode = PI_WFRX_SPI_MOSI;
wfRx[SCLK].gpio = SCLK;
wfRx[SCLK].mode = PI_WFRX_SPI_SCLK;
wfRx[CS].gpio = CS;
wfRx[CS].mode = PI_WFRX_SPI_CS;
wfRx[CS].baud = baud;
wfRx[CS].S.started = 0;
wfRx[CS].S.MISO = MISO;
wfRx[CS].S.MOSI = MOSI;
wfRx[CS].S.CS = CS;
wfRx[CS].S.SCLK = SCLK;
wfRx[CS].S.delay = 500000 / baud;
wfRx[CS].S.spiFlags = spiFlags;
wfRx[CS].S.MISOMode = gpioGetMode(MISO);
wfRx[CS].S.MOSIMode = gpioGetMode(MOSI);
wfRx[CS].S.CSMode = gpioGetMode(CS);
wfRx[CS].S.SCLKMode = gpioGetMode(SCLK);
myGpioSetMode(MISO, PI_INPUT);
myGpioSetMode(MOSI, PI_OUTPUT);
myGpioSetMode(CS, PI_OUTPUT);
myGpioSetMode(SCLK, PI_OUTPUT);
return 0;
}
/* ----------------------------------------------------------------------- */ /* ----------------------------------------------------------------------- */
@ -9937,6 +10160,87 @@ int bbI2CClose(unsigned SDA)
return 0; return 0;
} }
int bbSPIClose(unsigned CS)
{
DBG(DBG_USER, "CS=%d", CS);
CHECK_INITED;
if (CS > PI_MAX_USER_GPIO)
SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", CS);
switch(wfRx[CS].mode)
{
case PI_WFRX_SPI_CS:
myGpioSetMode(wfRx[CS].S.MISO, wfRx[CS].S.MISOMode);
myGpioSetMode(wfRx[CS].S.MOSI, wfRx[CS].S.MOSIMode);
myGpioSetMode(wfRx[CS].S.CS, wfRx[CS].S.CSMode);
myGpioSetMode(wfRx[CS].S.SCLK, wfRx[CS].S.SCLKMode);
wfRx[wfRx[CS].S.MISO].mode = PI_WFRX_NONE;
wfRx[wfRx[CS].S.MOSI].mode = PI_WFRX_NONE;
wfRx[wfRx[CS].S.CS].mode = PI_WFRX_NONE;
wfRx[wfRx[CS].S.SCLK].mode = PI_WFRX_NONE;
break;
default:
SOFT_ERROR(PI_NOT_SPI_GPIO, "no SPI on gpio (%d)", CS);
break;
}
return 0;
}
/*-------------------------------------------------------------------------*/
int bbSPIXfer(
unsigned CS,
char *inBuf,
char *outBuf,
unsigned len)
{
int pos, status;
wfRx_t *w;
DBG(DBG_USER, "gpio=%d inBuf=%s outBuf=%08X len=%d",
CS, myBuf2Str(len, (char *)inBuf), (int)outBuf, len);
CHECK_INITED;
if (CS > PI_MAX_USER_GPIO)
SOFT_ERROR(PI_BAD_USER_GPIO, "bad gpio (%d)", CS);
if (wfRx[CS].mode != PI_WFRX_SPI_CS)
SOFT_ERROR(PI_NOT_SPI_GPIO, "no SPI on gpio (%d)", CS);
if (!inBuf || !len)
SOFT_ERROR(PI_BAD_POINTER, "input buffer can't be NULL");
if (!outBuf && len)
SOFT_ERROR(PI_BAD_POINTER, "output buffer can't be NULL");
w = &wfRx[CS];
status = 0;
bbSPIStart(w);
for (pos=0; pos < len; pos++)
{
DBG(DBG_INTERNAL, "pos=%d len=%d sent=%d",
pos, len, inBuf[pos]);
outBuf[pos] = bbSPIXferByte(w, inBuf[pos]);
DBG(DBG_INTERNAL, "recvd=%d", outBuf[pos]);
}
bbSPIStop(w);
status = len;
return status;
}
/*-------------------------------------------------------------------------*/ /*-------------------------------------------------------------------------*/
int bbI2CZip( int bbI2CZip(

View File

@ -285,6 +285,10 @@ spiRead Reads bytes from a SPI device
spiWrite Writes bytes to a SPI device spiWrite Writes bytes to a SPI device
spiXfer Transfers bytes with a SPI device spiXfer Transfers bytes with a SPI device
bbSPIOpen Opens GPIO for bit banging SPI
bbSPIClose Closes GPIO for bit banging SPI
bbSPIXfer Performs multiple bit banged SPI transactions
SERIAL SERIAL
serOpen Opens a serial device serOpen Opens a serial device
@ -592,6 +596,9 @@ typedef void *(gpioThreadFunc_t) (void *);
#define PI_BB_I2C_MIN_BAUD 50 #define PI_BB_I2C_MIN_BAUD 50
#define PI_BB_I2C_MAX_BAUD 500000 #define PI_BB_I2C_MAX_BAUD 500000
#define PI_BB_SPI_MIN_BAUD 50
#define PI_BB_SPI_MAX_BAUD 500000
#define PI_BB_SER_MIN_BAUD 50 #define PI_BB_SER_MIN_BAUD 50
#define PI_BB_SER_MAX_BAUD 250000 #define PI_BB_SER_MAX_BAUD 250000
@ -2619,6 +2626,86 @@ SDA: 0-31, the SDA GPIO used in a prior call to [*bbI2COpen*]
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_I2C_GPIO. Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_I2C_GPIO.
D*/ D*/
/*F*/
int bbSPIOpen(unsigned CS, unsigned MISO, unsigned MOSI, unsigned SCLK, unsigned baud, unsigned spiFlags);
/*D
This function selects a set of GPIO for bit banging SPI at a
specified baud rate.
Bit banging SPI allows the use of different GPIO for SPI than
for the hardware SPI ports.
. .
CS: 0-31
MISO: 0-31
MOSI: 0-31
SCLK: 0-31
baud: 50-500000
spiFlags: see below
. .
spiFlags consists of the least significant 22 bits.
. .
21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
b b b b b b R T n n n n W A u2 u1 u0 p2 p1 p0 m m
. .
mm defines the SPI mode.
. .
Mode POL PHA
0 0 0
1 0 1
2 1 0
3 1 1
. .
p0 is 0 if CEx is active low (default) and 1 for active high.
The other bits in flags should be set to zero.
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, PI_BAD_SPI_BAUD, or
PI_GPIO_IN_USE.
D*/
/*F*/
int bbSPIClose(unsigned CS);
/*D
This function stops bit banging SPI on a set of GPIO previously
opened with [*bbSPIOpen*].
. .
CS: 0-31, the CS GPIO used in a prior call to [*bbSPIOpen*]
. .
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SPI_GPIO.
D*/
/*F*/
int bbSPIXfer(
unsigned CS,
char *inBuf,
char *outBuf,
unsigned len);
/*D
This function executes an bit banged SPI transfer. The data
to be sent is specified by the contents of inBuf, received data
is stored into outBuf.
len specifies the amount of bytes to be transferred.
. .
CS: 0-31 (as used in a prior call to [*bbSPIOpen*])
inBuf: pointer to buffer to hold data to be sent
outBuf: pointer to buffer to hold returned data
outLen: size of output buffer
. .
Returns >= 0 if OK (the number of bytes read), otherwise
PI_BAD_USER_GPIO, PI_NOT_SPI_GPIO or PI_BAD_POINTER.
The returned I2C data is stored in consecutive locations of outBuf.
D*/
/*F*/ /*F*/
int bbI2CZip( int bbI2CZip(
unsigned SDA, unsigned SDA,
@ -5450,6 +5537,10 @@ PARAMS*/
#define PI_CMD_SHELL 110 #define PI_CMD_SHELL 110
#define PI_CMD_BSPIC 111
#define PI_CMD_BSPIO 112
#define PI_CMD_BSPIX 113
/*DEF_E*/ /*DEF_E*/
/* /*
@ -5654,6 +5745,8 @@ after this command is issued.
#define PI_FILE_IS_A_DIR -138 // file is a directory #define PI_FILE_IS_A_DIR -138 // file is a directory
#define PI_BAD_SHELL_STATUS -139 // bad shell return status #define PI_BAD_SHELL_STATUS -139 // bad shell return status
#define PI_BAD_SCRIPT_NAME -140 // bad script name #define PI_BAD_SCRIPT_NAME -140 // bad script name
#define PI_BAD_SPI_BAUD -141 // bad SPI baud rate, not 50-500k
#define PI_NOT_SPI_GPIO -142 // no bit bang SPI in progress on GPIO
#define PI_PIGIF_ERR_0 -2000 #define PI_PIGIF_ERR_0 -2000
#define PI_PIGIF_ERR_99 -2099 #define PI_PIGIF_ERR_99 -2099

View File

@ -238,6 +238,10 @@ spi_read Reads bytes from a SPI device
spi_write Writes bytes to a SPI device spi_write Writes bytes to a SPI device
spi_xfer Transfers bytes with a SPI device spi_xfer Transfers bytes with a SPI device
bb_spi_open Opens GPIO for bit banging SPI
bb_spi_close Closes GPIO for bit banging SPI
bb_spi_xfer Transfers bytes with bit banging SPI
Serial Serial
serial_open Opens a serial device serial_open Opens a serial device
@ -497,6 +501,10 @@ _PI_CMD_FS =108
_PI_CMD_FL =109 _PI_CMD_FL =109
_PI_CMD_SHELL=110 _PI_CMD_SHELL=110
_PI_CMD_BSPIC=111
_PI_CMD_BSPIO=112
_PI_CMD_BSPIX=113
# pigpio error numbers # pigpio error numbers
_PI_INIT_FAILED =-1 _PI_INIT_FAILED =-1
@ -640,6 +648,8 @@ PI_NO_FILE_ACCESS =-137
PI_FILE_IS_A_DIR =-138 PI_FILE_IS_A_DIR =-138
PI_BAD_SHELL_STATUS =-139 PI_BAD_SHELL_STATUS =-139
PI_BAD_SCRIPT_NAME =-140 PI_BAD_SCRIPT_NAME =-140
PI_BAD_SPI_BAUD =-141
PI_NOT_SPI_GPIO =-142
# pigpio error text # pigpio error text
@ -782,7 +792,8 @@ _errors=[
[PI_FILE_IS_A_DIR , "file is a directory"], [PI_FILE_IS_A_DIR , "file is a directory"],
[PI_BAD_SHELL_STATUS , "bad shell return status"], [PI_BAD_SHELL_STATUS , "bad shell return status"],
[PI_BAD_SCRIPT_NAME , "bad script name"], [PI_BAD_SCRIPT_NAME , "bad script name"],
[PI_BAD_SPI_BAUD , "bad SPI baud rate, not 50-500k"],
[PI_NOT_SPI_GPIO , "no bit bang SPI in progress on GPIO"],
] ]
class _socklock: class _socklock:
@ -2946,6 +2957,62 @@ class pi():
return bytes, data return bytes, data
def bb_spi_open(self, CS, MISO, MOSI, SCLK, baud=100000, spi_flags=1):
"""
###
"""
# I p1 CS
# I p2 0
# I p3 20
## extension ##
# I MISO
# I MOSI
# I SCLK
# I baud
# I spi_flags
extents = [struct.pack("IIIII", MISO, MOSI, SCLK, baud, spi_flags)]
return _u2i(_pigpio_command_ext(
self.sl, _PI_CMD_BSPIO, CS, 0, 20, extents))
def bb_spi_close(self, CS):
"""
This function stops bit banging SPI on a set of GPIO
previously opened with [*bb_spi_open*].
CS:= 0-31, the CS GPIO used in a prior call to [*bb_ispi_open*]
Returns 0 if OK, otherwise PI_BAD_USER_GPIO, or PI_NOT_SPI_GPIO.
...
pi.bb_spi_close(CS)
...
"""
return _u2i(_pigpio_command(self.sl, _PI_CMD_BSPIC, CS, 0))
def bb_spi_xfer(self, CS, data):
"""
###
"""
# I p1 SDA
# I p2 0
# I p3 len
## extension ##
# s len data bytes
# Don't raise exception. Must release lock.
bytes = u2i(_pigpio_command_ext(
self.sl, _PI_CMD_BSPIX, CS, 0, len(data), [data], False))
if bytes > 0:
data = self._rxbuf(bytes)
else:
data = ""
self.sl.l.release()
return bytes, data
def bb_i2c_open(self, SDA, SCL, baud=100000): def bb_i2c_open(self, SDA, SCL, baud=100000):
""" """
This function selects a pair of GPIO for bit banging I2C at a This function selects a pair of GPIO for bit banging I2C at a