From 33a222f80b1fb373887cc646a3a19429f722c425 Mon Sep 17 00:00:00 2001 From: joan Date: Fri, 24 Jul 2015 21:17:29 +0100 Subject: [PATCH] V35 --- command.c | 78 +++-- pigpio.3 | 215 +++++++----- pigpio.c | 872 +++++++++++++++++++++++++++++++------------------ pigpio.h | 182 ++++++----- pigpio.py | 346 +++++++++++--------- pigpiod_if.3 | 177 +++++----- pigpiod_if.c | 2 +- pigpiod_if.h | 129 ++++---- pigs.1 | 156 +++++---- setup.py | 2 +- x_pigpio.c | 8 +- x_pigpio.py | 10 +- x_pigpiod_if.c | 8 +- x_pigs | 14 +- x_pipe | 16 +- 15 files changed, 1332 insertions(+), 883 deletions(-) diff --git a/command.c b/command.c index 1bdb901..41c35ff 100644 --- a/command.c +++ b/command.c @@ -26,7 +26,7 @@ For more information, please refer to */ /* -This version is for pigpio version 34+ +This version is for pigpio version 35+ */ #include @@ -458,11 +458,14 @@ static errInfo_t errInfo[]= {PI_BAD_I2C_RLEN , "bad I2C read length"}, {PI_BAD_I2C_CMD , "bad I2C command"}, {PI_BAD_I2C_BAUD , "bad I2C baud rate, not 50-500k"}, - {PI_BAD_REPEAT_CNT , "bad repeat count, not 2-max"}, - {PI_BAD_REPEAT_WID , "bad repeat wave id"}, - {PI_TOO_MANY_COUNTS , "too many chain counters"}, - {PI_BAD_CHAIN_CMD , "malformed chain command string"}, - {PI_REUSED_WID , "wave already used in chain"}, + {PI_CHAIN_LOOP_CNT , "bad chain loop count"}, + {PI_BAD_CHAIN_LOOP , "empty chain loop"}, + {PI_CHAIN_COUNTER , "too many chain counters"}, + {PI_BAD_CHAIN_CMD , "bad chain command"}, + {PI_BAD_CHAIN_DELAY , "bad chain delay micros"}, + {PI_CHAIN_NESTING , "chain counters nested too deeply"}, + {PI_CHAIN_TOO_BIG , "chain is too long"}, + {PI_DEPRECATED , "deprecated function removed"}, }; @@ -535,6 +538,7 @@ int cmdParse( char c; uint32_t tp1, tp2, tp3; int8_t to1, to2, to3; + int eaten; /* Check that ext is big enough for the largest message. */ if (ext_len < (4 * CMD_MAX_PARAM)) return CMD_EXT_TOO_SMALL; @@ -865,12 +869,16 @@ int cmdParse( while (pars < CMD_MAX_PARAM) { - ctl->eaten += getNum(buf+ctl->eaten, &tp1, &to1); - if ((to1 == CMD_NUMERIC) && - ((int)tp1>=0) && ((int)tp1<=255)) + eaten = getNum(buf+ctl->eaten, &tp1, &to1); + if (to1 == CMD_NUMERIC) { - pars++; - *p8++ = tp1; + if (((int)tp1>=0) && ((int)tp1<=255)) + { + pars++; + *p8++ = tp1; + ctl->eaten += eaten; + } + else break; /* invalid number, end of command */ } else break; } @@ -899,13 +907,16 @@ int cmdParse( while (pars < 32) { - ctl->eaten += getNum(buf+ctl->eaten, &tp1, &to1); - if ((to1 == CMD_NUMERIC) && - ((int)tp1>=0) && - ((int)tp1<=255)) + eaten = getNum(buf+ctl->eaten, &tp1, &to1); + if (to1 == CMD_NUMERIC) { - pars++; - *p8++ = tp1; + if (((int)tp1>=0) && ((int)tp1<=255)) + { + pars++; + *p8++ = tp1; + ctl->eaten += eaten; + } + else break; /* invalid number, end of command */ } else break; } @@ -940,15 +951,16 @@ int cmdParse( while (pars < CMD_MAX_PARAM) { - ctl->eaten += getNum(buf+ctl->eaten, &tp1, &to1); + eaten = getNum(buf+ctl->eaten, &tp1, &to1); if (to1 == CMD_NUMERIC) { if (((int)tp1>=0) && ((int)tp1<=255)) { pars++; *p8++ = tp1; + ctl->eaten += eaten; } - else valid = 0; + else break; } else break; } @@ -996,12 +1008,16 @@ int cmdParse( p8 = ext + 12; while (pars < CMD_MAX_PARAM) { - ctl->eaten += getNum(buf+ctl->eaten, &tp1, &to1); - if ((to1 == CMD_NUMERIC) && - ((int)tp1>=0) && ((int)tp1<=255)) + eaten = getNum(buf+ctl->eaten, &tp1, &to1); + if (to1 == CMD_NUMERIC) { - *p8++ = tp1; - pars++; + if (((int)tp1>=0) && ((int)tp1<=255)) + { + *p8++ = tp1; + pars++; + ctl->eaten += eaten; + } + else break; /* invalid number, end of command */ } else break; } @@ -1022,12 +1038,16 @@ int cmdParse( while (pars < CMD_MAX_PARAM) { - ctl->eaten += getNum(buf+ctl->eaten, &tp1, &to1); - if ((to1 == CMD_NUMERIC) && - ((int)tp1>=0) && ((int)tp1<=255)) + eaten = getNum(buf+ctl->eaten, &tp1, &to1); + if (to1 == CMD_NUMERIC) { - pars++; - *p8++ = tp1; + if (((int)tp1>=0) && ((int)tp1<=255)) + { + pars++; + *p8++ = tp1; + ctl->eaten += eaten; + } + else break; /* invalid number, end of command */ } else break; } diff --git a/pigpio.3 b/pigpio.3 index 8d948bb..0006337 100644 --- a/pigpio.3 +++ b/pigpio.3 @@ -1683,8 +1683,9 @@ gpioWaveAddSerial(4, 9600, 8, 2, 1000000, MSG_LEN, data); .IP "\fBint gpioWaveCreate(void)\fP" .IP "" 4 This function creates a waveform from the data provided by the prior -calls to the \fBgpioWaveAdd*\fP functions. Upon success a positive wave id -is returned. +calls to the \fBgpioWaveAdd*\fP functions. Upon success a wave id +greater than or equal to 0 is returned, otherwise PI_EMPTY_WAVEFORM, +PI_TOO_MANY_CBS, PI_TOO_MANY_OOL, or PI_NO_WAVEFORM_ID. .br @@ -1788,8 +1789,7 @@ PI_NO_WAVEFORM_ID, PI_TOO_MANY_CBS, or PI_TOO_MANY_OOL. .IP "\fBint gpioWaveDelete(unsigned wave_id)\fP" .IP "" 4 -This function deletes all created waveforms with ids greater than or -equal to wave_id. +This function deletes the waveform with id wave_id. .br @@ -1811,38 +1811,6 @@ Wave ids are allocated in order, 0, 1, 2, etc. .br Returns 0 if OK, otherwise PI_BAD_WAVE_ID. -.IP "\fBint gpioWaveTxStart(unsigned wave_mode)\fP" -.IP "" 4 -This function creates and then transmits a waveform. The mode -determines whether the waveform is sent once or cycles endlessly. - -.br - -.br -NOTE: Any hardware PWM started by \fBgpioHardwarePWM\fP will be cancelled. - -.br - -.br - -.EX -wave_mode: 0 (PI_WAVE_MODE_ONE_SHOT), 1 (PI_WAVE_MODE_REPEAT) -.br - -.EE - -.br - -.br -This function is deprecated and should no longer be used. Use -\fBgpioWaveCreate\fP and \fBgpioWaveTxSend\fP instead. - -.br - -.br -Returns the number of DMA control blocks in the waveform if OK, -otherwise PI_BAD_WAVE_MODE. - .IP "\fBint gpioWaveTxSend(unsigned wave_id, unsigned wave_mode)\fP" .IP "" 4 This function transmits the waveform with id wave_id. The mode @@ -1884,7 +1852,7 @@ NOTE: Any hardware PWM started by \fBgpioHardwarePWM\fP will be cancelled. .br The waves to be transmitted are specified by the contents of buf -which contains an ordered list of wave_ids and optional command +which contains an ordered list of \fBwave_id\fPs and optional command codes and related data. .br @@ -1902,24 +1870,26 @@ bufSize: the number of bytes in buf .br .br -Returns 0 if OK, otherwise PI_BAD_REPEAT_CNT, PI_BAD_REPEAT_WID, -PI_BAD_CHAIN_CMD, PI_TOO_MANY_COUNTS, or PI_BAD_WAVE_ID. +Returns 0 if OK, otherwise PI_CHAIN_NESTING, PI_CHAIN_LOOP_CNT, PI_BAD_CHAIN_LOOP, PI_BAD_CHAIN_CMD, PI_CHAIN_COUNTER, +PI_BAD_CHAIN_DELAY, PI_CHAIN_TOO_BIG, or PI_BAD_WAVE_ID. .br .br -Each wave is transmitted in the order specified. A wave may only -occur once per chain. Waves may be transmitted multiple times by -using the repeat command. The repeat command specifies a wave id -and a count. The wave id must occur earlier in the chain. All the -waves between wave id and the repeat command are transmitted count -times. +Each wave is transmitted in the order specified. A wave may +occur multiple times per chain. .br .br -Repeat commands may not be nested. The minimum repeat count is 2. -A maximum of 5 repeat commands is supported per chain. +A blocks of waves may be transmitted multiple times by using +the loop commands. The block is bracketed by loop start and +end commands. Loops may be nested. + +.br + +.br +Delays between waves may be added with the delay command. .br @@ -1929,13 +1899,24 @@ The following command codes are supported: .br .br -Name Cmd & Data Meaning +Name Cmd & Data Meaning .br -Repeat 255 wid C0 C1 C2 Repeat from wid count times +Loop Start 255 0 Identify start of a wave block .br -count = C0 + C1*256 + C2*65536 +Loop Repeat 255 1 x y loop x + y*256 times + +.br +Delay 255 2 x y delay x + y*256 microseconds + +.br + +.br + +.br +The code is currently dimensioned to support a chain with roughly +600 entries and 20 loop counters. .br @@ -1944,55 +1925,109 @@ count = C0 + C1*256 + C2*65536 .br .EX -The following examples assume that waves with ids 0 to 12 exist. +#include +.br +#include .br .br -// 0 255 0 57 0 0 (repeat 0 57 times) +#define WAVES 5 .br -status = gpioWaveChain((char []){0, 255, 0, 57, 0, 0}, 6); +#define GPIO 4 .br .br -// 0 1 255 0 0 2 0 (repeat 0+1 512 times) +int main(int argc, char *argv[]) .br -status = gpioWaveChain((char []){0, 1, 255, 0, 0, 2, 0}, 7); +{ +.br + int i, wid[WAVES]; .br .br -// 0 1 255 1 0 0 1 (transmit 0, repeat 1 65536 times) -.br -status = gpioWaveChain((char []){0, 1, 255, 1, 0, 0, 1}, 7); + if (gpioInitialise()<0) return -1; .br .br -// 0 1 2 3 255 2 13 0 0 (transmit 0+1, repeat 2+3 13 times) -.br -status = gpioWaveChain( -.br - (char []){0, 1, 2, 3, 255, 2, 13, 0, 0}, 9); + gpioSetMode(GPIO, PI_OUTPUT); .br .br -// The following repeats 5 65793 times, transmits 6, -.br -// repeats 7+8 514 times, transmits 12, -.br -// repeats 9+11+10 197121 times. -.br -// 5 255 5 1 1 1 6 7 8 255 7 2 2 0 12 9 11 10 255 9 1 2 3 -.br -char chain[] = { -.br - 5, 255, 5, 1, 1, 1, -.br - 6, 7, 8, 255, 7, 2, 2, 0, -.br - 12, 9, 11, 10, 255, 9, 1, 2, 3}; + printf("start piscope, press return\n"); getchar(); .br .br -status = gpioWaveChain(chain, sizeof(chain)); + for (i=0; i */ -/* pigpio version 34 */ +/* pigpio version 35 */ /* include ------------------------------------------------------- */ @@ -626,7 +626,10 @@ bit 0 READ_LAST_NOT_SET_ERROR #define NORMAL_DMA (DMA_NO_WIDE_BURSTS | DMA_WAIT_RESP) -#define TIMED_DMA(x) (DMA_DEST_DREQ | DMA_PERIPHERAL_MAPPING(x)) +#define TIMED_DMA(x) (DMA_DEST_DREQ | DMA_PERIPHERAL_MAPPING(x)) + +#define PCM_TIMER (((PCM_BASE + PCM_FIFO*4) & 0x00ffffff) | PI_PERI_BUS) +#define PWM_TIMER (((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | PI_PERI_BUS) #define DBG_MIN_LEVEL 0 #define DBG_ALWAYS 0 @@ -669,6 +672,28 @@ bit 0 READ_LAST_NOT_SET_ERROR #define CBS_PER_OPAGE 118 #define OOL_PER_OPAGE 79 +/* +Wave Count Block + +Assumes two counters per block. Each counter 4 * 16 (16^4=65536) + 0 CB [13] 13*8 104 CBs for counter 0 + 104 CB [13] 13*8 104 CBs for counter 1 + 208 CB [60] 60*8 480 CBs reserved to construct wave + 688 OOL [60] 60*1 60 OOL reserved to construct wave + 748 OOL[136] 136*1 136 OOL for counter 0 + 884 OOL[136] 136*1 136 OOL for counter 1 +1020 pad [4] 4*1 4 spare +*/ + +#define WCB_CNT_PER_PAGE 2 +#define WCB_COUNTERS (WCB_CNT_PER_PAGE * PI_WAVE_COUNT_PAGES) +#define WCB_CNT_CBS 13 +#define WCB_CNT_OOL 68 +#define WCB_COUNTER_OOL (WCB_CNT_PER_PAGE * WCB_CNT_OOL) +#define WCB_COUNTER_CBS (WCB_CNT_PER_PAGE * WCB_CNT_CBS) +#define WCB_CHAIN_CBS 60 +#define WCB_CHAIN_OOL 60 + #define CBS_PER_CYCLE ((PULSE_PER_CYCLE*3)+2) #define NUM_CBS (CBS_PER_CYCLE * bufferCycles) @@ -1086,9 +1111,8 @@ static rawWaveInfo_t waveInfo[PI_MAX_WAVES]; static wfRx_t wfRx[PI_MAX_USER_GPIO+1]; -static int waveOutBotCB = PI_WAVE_COUNTERS*CBS_PER_OPAGE; -static int waveOutTopCB = NUM_WAVE_CBS; -static int waveOutBotOOL = PI_WAVE_COUNTERS*OOL_PER_OPAGE; +static int waveOutBotCB = PI_WAVE_COUNT_PAGES*CBS_PER_OPAGE; +static int waveOutBotOOL = PI_WAVE_COUNT_PAGES*OOL_PER_OPAGE; static int waveOutTopOOL = NUM_WAVE_OOL; static int waveOutCount = 0; @@ -1312,6 +1336,9 @@ static void initHWClk static void initDMAgo(volatile uint32_t *dmaAddr, uint32_t cbAddr); +int gpioWaveTxStart(unsigned wave_mode); /* deprecated */ + + /* ======================================================================= */ static char * myTimeStamp() @@ -2461,19 +2488,6 @@ static uint32_t waveOOLPOadr(int pos) } -/* ----------------------------------------------------------------------- */ - -static void waveCbOPrint(int pos) -{ - rawCbs_t * p; - - p = rawWaveCBAdr(pos); - - fprintf(stderr, "i=%x s=%x d=%x len=%x s=%x nxt=%x\n", - p->info, p->src, p->dst, p->length, p->stride, p->next); -} - - /* ----------------------------------------------------------------------- */ static void waveBitDelay @@ -2501,20 +2515,42 @@ static void waveBitDelay /* ----------------------------------------------------------------------- */ -static int errCBsOOL(int cb, int botOOL, int topOOL) +static void waveCBsOOLs(int *numCBs, int *numBOOLs, int *numTOOLs) { - if (cb >= waveOutTopCB) return PI_TOO_MANY_CBS; + int numCB=0, numBOOL=0, numTOOL=0; - if (botOOL >= topOOL) return PI_TOO_MANY_OOL; + unsigned i; - return 0; + unsigned numWaves; + + rawWave_t *waves; + + numWaves = wfc[wfcur]; + waves = wf [wfcur]; + + /* delay cb at start of DMA */ + + numCB++; + + for (i=0; iinfo = NORMAL_DMA | - DMA_DEST_DREQ | - DMA_PERIPHERAL_MAPPING(2); - p->dst = ((PCM_BASE + PCM_FIFO*4) & 0x00ffffff) | PI_PERI_BUS; + p->info = NORMAL_DMA | TIMED_DMA(2); + p->dst = PCM_TIMER; } else { - p->info = NORMAL_DMA | - DMA_DEST_DREQ | - DMA_PERIPHERAL_MAPPING(5); - p->dst = ((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | PI_PERI_BUS; + p->info = NORMAL_DMA | TIMED_DMA(5); + p->dst = PWM_TIMER; } p->src = (uint32_t) (&dmaOBus[0]->periphData); @@ -2564,8 +2594,6 @@ static int wave2Cbs(unsigned wave_mode) { if (waves[i].gpioOn) { - if ((status = errCBsOOL(botCB+1, botOOL+1, topOOL))) return status; - waveSetOOL(botOOL, waves[i].gpioOn); p = rawWaveCBAdr(botCB++); @@ -2579,8 +2607,6 @@ static int wave2Cbs(unsigned wave_mode) if (waves[i].gpioOff) { - if ((status = errCBsOOL(botCB+1, botOOL+1, topOOL))) return status; - waveSetOOL(botOOL, waves[i].gpioOff); p = rawWaveCBAdr(botCB++); @@ -2594,8 +2620,6 @@ static int wave2Cbs(unsigned wave_mode) if (waves[i].flags & WAVE_FLAG_READ) { - if ((status = errCBsOOL(botCB+1, botOOL, topOOL-1))) return status; - p = rawWaveCBAdr(botCB++); p->info = NORMAL_DMA; @@ -2607,8 +2631,6 @@ static int wave2Cbs(unsigned wave_mode) if (waves[i].flags & WAVE_FLAG_TICK) { - if ((status = errCBsOOL(botCB+1, botOOL, topOOL-1))) return status; - p = rawWaveCBAdr(botCB++); p->info = NORMAL_DMA; @@ -2620,27 +2642,19 @@ static int wave2Cbs(unsigned wave_mode) if (waves[i].usDelay) { - if ((status = errCBsOOL(botCB+1, botOOL, topOOL))) return status; - p = rawWaveCBAdr(botCB++); /* use the secondary clock */ if (gpioCfg.clockPeriph != PI_CLOCK_PCM) { - p->info = NORMAL_DMA | - DMA_DEST_DREQ | - DMA_PERIPHERAL_MAPPING(2); - - p->dst = ((PCM_BASE + PCM_FIFO*4) & 0x00ffffff) | PI_PERI_BUS; + p->info = NORMAL_DMA | TIMED_DMA(2); + p->dst = PCM_TIMER; } else { - p->info = NORMAL_DMA | - DMA_DEST_DREQ | - DMA_PERIPHERAL_MAPPING(5); - - p->dst = ((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | PI_PERI_BUS; + p->info = NORMAL_DMA | TIMED_DMA(5); + p->dst = PWM_TIMER; } p->src = (uint32_t) (&dmaOBus[0]->periphData); @@ -2656,113 +2670,15 @@ static int wave2Cbs(unsigned wave_mode) else p->next = waveCbPOadr(repeatCB); } - status = botCB - waveOutBotCB; + status = botCB - *CB; - waveOutBotCB = botCB; - waveOutBotOOL = botOOL; - waveOutTopOOL = topOOL; + *CB = botCB; + *BOOL = botOOL; + *TOOL = topOOL; return status; } -/* ----------------------------------------------------------------------- */ - -static uint32_t waveGetIn(int page, int slot) -{ - return (dmaOVirt[page]->OOL[slot]); -} - -static void waveSetIn(int page, int slot, uint32_t value) -{ - dmaOVirt[page]->OOL[slot] = value; -} - -static uint32_t myWaveOOLPOadr(int page, int slot) -{ - return (uint32_t) &dmaOBus[page]->OOL[slot]; -} - -static void waveCount( - unsigned counter, - unsigned blklen, - unsigned blocks, - unsigned count, - uint32_t repeat, - uint32_t next) -{ - rawCbs_t *p=NULL; - - int b, baseCB, dig; - uint32_t nxt; - - int botCB; - - botCB = counter * CBS_PER_OPAGE; - - baseCB = botCB; - - /* set up all the OOLs */ - for (b=0; b < (blocks*(blklen+1)); b++) waveSetIn(counter, b, repeat); - - for (b=0; binfo = NORMAL_DMA; - - p->src = myWaveOOLPOadr(counter, b*(blklen+1)); - p->dst = (waveCbPOadr(botCB+1) + 20); - - p->length = 4; - p->next = waveCbPOadr(botCB); - - /* copy BOTTOM to TOP */ - - p = rawWaveCBAdr(botCB++); - - p->info = NORMAL_DMA; - - p->src = myWaveOOLPOadr(counter, b*(blklen+1)); - p->dst = myWaveOOLPOadr(counter, (b*(blklen+1))+blklen); - - p->length = 4; - p->next = waveCbPOadr(botCB); - - /* shift all down one */ - - p = rawWaveCBAdr(botCB++); - - p->info = NORMAL_DMA|DMA_SRC_INC|DMA_DEST_INC; - - p->src = myWaveOOLPOadr(counter, ((b*(blklen+1))+1)); - p->dst = myWaveOOLPOadr(counter, ((b*(blklen+1))+0)); - - p->length = blklen*4; - p->next = repeat; - } - - b = 0; - - while (count && (binfo = NORMAL_DMA | TIMED_DMA(2); - p->dst = ((PCM_BASE + PCM_FIFO*4) & 0x00ffffff) | PI_PERI_BUS; + p->info = NORMAL_DMA | TIMED_DMA(2); + p->dst = PCM_TIMER; } else { - p->info = NORMAL_DMA | TIMED_DMA(5); - p->dst = ((PWM_BASE + PWM_FIFO*4) & 0x00ffffff) | PI_PERI_BUS; + p->info = NORMAL_DMA | TIMED_DMA(5); + p->dst = PWM_TIMER; } p->src = dmaPwmDataAdr(b%DMAI_PAGES); @@ -7463,9 +7379,6 @@ void gpioTerminate(void) static void switchFunctionOff(unsigned gpio) { - unsigned clock, pwm; - int cctl[] = {CLK_GP0_CTL, CLK_GP1_CTL, CLK_GP2_CTL}; - switch (gpioInfo[gpio].is) { case GPIO_SERVO: @@ -7481,17 +7394,12 @@ static void switchFunctionOff(unsigned gpio) break; case GPIO_HW_CLK: - /* switch hardware clock off */ - clock = (clkDef[gpio] >> 4) & 3; - clkReg[cctl[clock]] = CLK_PASSWD | CLK_CTL_KILL; + /* No longer disable clock hardware, doing that was a bug. */ gpioInfo[gpio].width = 0; break; case GPIO_HW_PWM: - /* switch hardware PWM off */ - pwm = (PWMDef[gpio] >> 4) & 3; - if (pwm == 0) pwmReg[PWM_CTL] &= (~PWM_CTL_PWEN1); - else pwmReg[PWM_CTL] &= (~PWM_CTL_PWEN2); + /* No longer disable PWM hardware, doing that was a bug. */ gpioInfo[gpio].width = 0; break; } @@ -7499,14 +7407,18 @@ static void switchFunctionOff(unsigned gpio) static void stopHardwarePWM(void) { - int i; + unsigned i, pwm; for (i=0; i<= PI_MAX_GPIO; i++) { if (gpioInfo[i].is == GPIO_HW_PWM) { - switchFunctionOff(i); + pwm = (PWMDef[i] >> 4) & 3; + if (pwm == 0) pwmReg[PWM_CTL] &= (~PWM_CTL_PWEN1); + else pwmReg[PWM_CTL] &= (~PWM_CTL_PWEN2); + + gpioInfo[i].width = 0; gpioInfo[i].is = GPIO_UNDEFINED; } } @@ -7953,9 +7865,8 @@ int gpioWaveClear(void) wfStats.pulses = 0; wfStats.cbs = 0; - waveOutBotCB = PI_WAVE_COUNTERS*CBS_PER_OPAGE; - waveOutTopCB = NUM_WAVE_CBS; - waveOutBotOOL = PI_WAVE_COUNTERS*OOL_PER_OPAGE; + waveOutBotCB = PI_WAVE_COUNT_PAGES*CBS_PER_OPAGE; + waveOutBotOOL = PI_WAVE_COUNT_PAGES*OOL_PER_OPAGE; waveOutTopOOL = NUM_WAVE_OOL; waveOutCount = 0; @@ -8041,7 +7952,8 @@ int gpioWaveAddSerial if ((baud < PI_WAVE_MIN_BAUD) || (baud > PI_WAVE_MAX_BAUD)) SOFT_ERROR(PI_BAD_WAVE_BAUD, "bad baud rate (%d)", baud); - if ((data_bits < PI_MIN_WAVE_DATABITS) || (data_bits > PI_MAX_WAVE_DATABITS)) + if ((data_bits < PI_MIN_WAVE_DATABITS) || + (data_bits > PI_MAX_WAVE_DATABITS)) SOFT_ERROR(PI_BAD_DATABITS, "bad number of databits (%d)", data_bits); if ((stop_bits < PI_MIN_WAVE_HALFSTOPBITS) || @@ -8286,7 +8198,9 @@ int rawWaveAddSPI( int gpioWaveCreate(void) { - int cb; + int i, wid; + int numCB, numBOOL, numTOOL; + int CB, BOOL, TOOL; DBG(DBG_USER, ""); @@ -8294,22 +8208,86 @@ int gpioWaveCreate(void) if (wfc[wfcur] == 0) return PI_EMPTY_WAVEFORM; - if (waveOutCount < PI_MAX_WAVES) + /* What resources are needed? */ + + waveCBsOOLs(&numCB, &numBOOL, &numTOOL); + + wid = -1; + + /* Is there an exact fit with a deleted wave. */ + + for (i=0; i= NUM_WAVE_CBS) + return PI_TOO_MANY_CBS; + + if ((numBOOL+waveOutBotOOL) >= (waveOutTopOOL-numTOOL)) + return PI_TOO_MANY_OOL; + + if (wid >= PI_MAX_WAVES) + return PI_NO_WAVEFORM_ID; + + wid = waveOutCount++; + + waveInfo[wid].botCB = waveOutBotCB; + waveInfo[wid].topCB = waveOutBotCB + numCB -1; + waveInfo[wid].botOOL = waveOutBotOOL; + waveInfo[wid].topOOL = waveOutTopOOL; + waveInfo[wid].numCB = numCB; + waveInfo[wid].numBOOL = numBOOL; + waveInfo[wid].numTOOL = numTOOL; + + waveOutBotCB += numCB; + waveOutBotOOL += numBOOL; + waveOutTopOOL -= numTOOL; + } + + /* Must be room if got this far. */ + + CB = waveInfo[wid].botCB; + BOOL = waveInfo[wid].botOOL; + TOOL = waveInfo[wid].topOOL; + + wave2Cbs(PI_WAVE_MODE_ONE_SHOT, &CB, &BOOL, &TOOL); + + /* Sanity check. */ + + if ( (numCB != (CB-waveInfo[wid].botCB)) || + (numBOOL != (BOOL-waveInfo[wid].botOOL)) || + (numTOOL != (waveInfo[wid].topOOL-TOOL)) ) + { + DBG(0, "ERROR wid=%d CBs %d=%d BOOL %d=%d TOOL %d=%d", wid, + numCB, CB-waveInfo[wid].botCB, + numBOOL, BOOL-waveInfo[wid].botOOL, + numTOOL, waveInfo[wid].topOOL-TOOL); + } + + waveInfo[wid].deleted = 0; + + /* Consume waves. */ + + wfc[0] = 0; + wfc[1] = 0; + wfc[2] = 0; + + wfcur = 0; + + return wid; } /* ----------------------------------------------------------------------- */ @@ -8320,14 +8298,23 @@ int gpioWaveDelete(unsigned wave_id) CHECK_INITED; - if (wave_id >= waveOutCount) + if ((wave_id >= waveOutCount) || waveInfo[wave_id].deleted) SOFT_ERROR(PI_BAD_WAVE_ID, "bad wave id (%d)", wave_id); - waveOutBotCB = waveInfo[wave_id].botCB; - waveOutBotOOL = waveInfo[wave_id].botOOL; - waveOutTopOOL = waveInfo[wave_id].topOOL; + waveInfo[wave_id].deleted = 1; - waveOutCount = wave_id; + if (wave_id == (waveOutCount-1)) + { + /* top wave deleted, garbage collect any other deleted waves */ + + while ((wave_id > 0) && (waveInfo[wave_id-1].deleted)) --wave_id; + + waveOutBotCB = waveInfo[wave_id].botCB; + waveOutBotOOL = waveInfo[wave_id].botOOL; + waveOutTopOOL = waveInfo[wave_id].topOOL; + + waveOutCount = wave_id; + } return 0; } @@ -8336,53 +8323,11 @@ int gpioWaveDelete(unsigned wave_id) int gpioWaveTxStart(unsigned wave_mode) { - /* This function is deprecated and will be removed. */ - - int firstCB=PI_WAVE_COUNTERS*CBS_PER_OPAGE; - int numCBs, i; - - DBG(DBG_USER, "wave_mode=%d", wave_mode); + /* This function is deprecated and has been removed. */ CHECK_INITED; - if (wave_mode > PI_WAVE_MODE_REPEAT) - SOFT_ERROR(PI_BAD_WAVE_MODE, "bad wave mode (%d)", wave_mode); - - if (wfc[wfcur] == 0) return 0; - - if (!waveClockInited) - { - stopHardwarePWM(); - initClock(0); /* initialise secondary clock */ - waveClockInited = 1; - } - - dmaOut[DMA_CS] = DMA_CHANNEL_RESET; - - dmaOut[DMA_CONBLK_AD] = 0; - - waveOutBotCB = firstCB; - waveOutTopCB = NUM_WAVE_CBS; - waveOutBotOOL = PI_WAVE_COUNTERS*OOL_PER_OPAGE; - waveOutTopOOL = NUM_WAVE_OOL; - - waveOutCount = 0; - - numCBs = wave2Cbs(wave_mode); - - if (numCBs > 0) - { - if (gpioCfg.dbgLevel >= DBG_SLOW_TICK) - { - fprintf(stderr, "*** OUTPUT DMA CONTROL BLOCKS ***\n"); - for (i=0; i= waveOutCount) + if ((wave_id >= waveOutCount) || waveInfo[wave_id].deleted) SOFT_ERROR(PI_BAD_WAVE_ID, "bad wave id (%d)", wave_id); if (wave_mode > PI_WAVE_MODE_REPEAT) @@ -8425,16 +8370,201 @@ int gpioWaveTxSend(unsigned wave_id, unsigned wave_mode) return (waveInfo[wave_id].topCB - waveInfo[wave_id].botCB) + 1; } + /* ----------------------------------------------------------------------- */ +static int chainGetCB(int n) +{ + int block, index; + + if (n < (WCB_CHAIN_CBS * PI_WAVE_COUNT_PAGES)) + { + block = n / WCB_CHAIN_CBS; + index = n % WCB_CHAIN_CBS; + return (block*CBS_PER_OPAGE) + WCB_COUNTER_CBS + index; + } + return -1; +} + +static void chainSetVal(int n, uint32_t val) +{ + int block, index; + uint32_t *p; + + if (n < (WCB_CHAIN_OOL * PI_WAVE_COUNT_PAGES)) + { + block = n / WCB_CHAIN_OOL; + index = n % WCB_CHAIN_OOL; + p = (uint32_t *) dmaOVirt[block] + (WCB_COUNTER_CBS+WCB_CHAIN_CBS) * 8; + p[index] = val; + } +} + +static uint32_t chainGetValPadr(int n) +{ + int block, index; + uint32_t *p; + + if (n < (WCB_CHAIN_OOL * PI_WAVE_COUNT_PAGES)) + { + block = n / WCB_CHAIN_OOL; + index = n % WCB_CHAIN_OOL; + p = (uint32_t *) dmaOBus[block] + (WCB_COUNTER_CBS+WCB_CHAIN_CBS) * 8; + return (uint32_t) (p + index); + } + return 0; +} + +static uint32_t chainGetCntVal(int counter, int slot) +{ + uint32_t *p; + int page, offset; + page = counter / 2; + offset = (counter % 2 ? WCB_COUNTER_OOL : 0); + p = (uint32_t *) dmaOVirt[page] + (WCB_COUNTER_CBS+WCB_CHAIN_CBS) * 8; + return p[WCB_CHAIN_OOL+ offset + slot]; +} + +static void chainSetCntVal(int counter, int slot, uint32_t value) +{ + uint32_t *p; + int page, offset; + page = counter / 2; + offset = (counter % 2 ? WCB_COUNTER_OOL : 0); + p = (uint32_t *) dmaOVirt[page] + (WCB_COUNTER_CBS+WCB_CHAIN_CBS) * 8; + p[WCB_CHAIN_OOL + offset + slot] = value; +} + +static uint32_t chainGetCntValPadr(int counter, int slot) +{ + uint32_t *p; + int page, offset; + page = counter / 2; + offset = (counter % 2 ? WCB_COUNTER_OOL : 0); + p = (uint32_t *) dmaOBus[page] + (WCB_COUNTER_CBS+WCB_CHAIN_CBS) * 8; + return (uint32_t)(p + WCB_CHAIN_OOL + offset + slot); +} + +static int chainGetCntCB(int counter) +{ + int page, offset; + page = counter / 2; + offset = (counter % 2 ? WCB_CNT_CBS : 0); + return ((page * CBS_PER_OPAGE) + offset); +} + +static void chainMakeCounter( + unsigned counter, + unsigned blklen, + unsigned blocks, + unsigned count, + uint32_t repeat, + uint32_t next) +{ + rawCbs_t *p=NULL; + + int b, baseCB, dig; + uint32_t nxt; + + int botCB; + + botCB = chainGetCntCB(counter); + + baseCB = botCB; + + /* set up all the OOLs */ + for (b=0; b < (blocks*(blklen+1)); b++) chainSetCntVal(counter, b, repeat); + + for (b=0; binfo = NORMAL_DMA; + + p->src = chainGetCntValPadr(counter, b*(blklen+1)); + p->dst = (waveCbPOadr(botCB+1) + 20); + + p->length = 4; + p->next = waveCbPOadr(botCB); + + /* copy BOTTOM to TOP */ + + p = rawWaveCBAdr(botCB++); + + p->info = NORMAL_DMA; + + p->src = chainGetCntValPadr(counter, b*(blklen+1)); + p->dst = chainGetCntValPadr(counter, (b*(blklen+1))+blklen); + + p->length = 4; + p->next = waveCbPOadr(botCB); + + /* shift all down one */ + + p = rawWaveCBAdr(botCB++); + + p->info = NORMAL_DMA|DMA_SRC_INC|DMA_DEST_INC; + + p->src = chainGetCntValPadr(counter, ((b*(blklen+1))+1)); + p->dst = chainGetCntValPadr(counter, ((b*(blklen+1))+0)); + + p->length = blklen*4; + p->next = repeat; + } + + /* reset the counter */ + + p = rawWaveCBAdr(botCB); + + p->info = NORMAL_DMA|DMA_SRC_INC|DMA_DEST_INC; + + p->src = chainGetCntValPadr(counter, blocks*(blklen+1)); + p->dst = chainGetCntValPadr(counter, 0); + + p->length = blocks*(blklen+1)*4; + p->next = next; + + b = 0; + + while (count && (binfo = NORMAL_DMA | TIMED_DMA(2); + p->dst = PCM_TIMER; + } + else + { + p->info = NORMAL_DMA | TIMED_DMA(5); + p->dst = PWM_TIMER; + } + + p->src = (uint32_t) (&dmaOBus[0]->periphData); + p->length = 4 * 20 / PI_WF_MICROS; /* 20 micros delay */ + p->next = waveCbPOadr(chainGetCB(cb)); counters = 0; wid = -1; - lastCB = -1; - firstCB = -1; i = 0; @@ -8464,92 +8611,183 @@ int gpioWaveChain(char *buf, unsigned bufSize) { wid = (unsigned)buf[i]; - if (wid == 255) /* repeat wave command */ + if (wid == 255) /* wave command */ { - if (counters < PI_WAVE_COUNTERS) + if ((i+2) > bufSize) + SOFT_ERROR(PI_BAD_CHAIN_CMD, + "incomplete chain command (at %d)", i); + + cmd = buf[i+1]; + + if (cmd == 0) /* loop begin */ { - if ((i+4) < bufSize) - { - rwid = buf[i+1]; - if ((i+5) < bufSize) - { - nwid = buf[i+5]; - if (nwid < waveOutCount) - next = waveCbPOadr(1+waveInfo[nwid].botCB); - else next = 0; /* error, will be picked up later */ - } - else next = 0; - if (used[rwid] == counters) - { - repeat = waveCbPOadr(1+waveInfo[rwid].botCB); + if (stk_lev >= (sizeof(stk_pos)/sizeof(int))) + SOFT_ERROR(PI_CHAIN_NESTING, + "chain counters nested too deep (at %d)", i); - cycles = (unsigned)buf[i+2] + - ((unsigned)buf[i+3]<<8) + - ((unsigned)buf[i+4]<<16); - - i+=4; - - if ((cycles > 1) && (cycles < PI_MAX_WAVE_CYCLES)) - { - --cycles; - - waveCount(counters, blklen, blocks, cycles, repeat, next); - - p = rawWaveCBAdr(lastCB); - - lastCB = -1; - - p->next = waveCbPOadr(counters * CBS_PER_OPAGE); - - counters++; - } - else SOFT_ERROR(PI_BAD_REPEAT_CNT, - "bad chain repeat count (%d)", cycles); - } - else SOFT_ERROR(PI_BAD_REPEAT_WID, - "bad chain repeat wave (%d)", rwid); - } - else SOFT_ERROR(PI_BAD_CHAIN_CMD, - "bad chain command (at char %d)", i); + stk_pos[stk_lev++] = cb; + i += 2; } - else SOFT_ERROR(PI_TOO_MANY_COUNTS, - "too many chain counters (at char %d)", i); + else if (cmd == 1) /* loop end */ + { + if (counters >= WCB_COUNTERS) + SOFT_ERROR(PI_CHAIN_COUNTER, + "too many chain counters (at %d)", i); + + if ((i+4) > bufSize) + SOFT_ERROR(PI_BAD_CHAIN_CMD, + "incomplete chain command (at %d)", i); + + loop = 0; + if (--stk_lev >= 0) loop = stk_pos[stk_lev]; + + if ((loop < 1) || (loop == cb)) + SOFT_ERROR(PI_BAD_CHAIN_LOOP, + "empty chain loop (at %d)", i); + + cycles = ((unsigned)buf[i+3] << 8) + (unsigned)buf[i+2]; + + i += 4; + + if (cycles > PI_MAX_WAVE_CYCLES) + SOFT_ERROR(PI_CHAIN_LOOP_CNT, + "bad chain loop count (%d)", cycles); + + if (cycles == 0) + { + /* Skip the complete loop block. Change + the next pointing to the start of the + loop block to the current cb. + */ + p = rawWaveCBAdr(chainGetCB(loop)); + p->next = waveCbPOadr(chainGetCB(cb)); + } + else if (cycles == 1) + { + /* Nothing to do, no need for a counter. */ + } + else + { + chaincb = chainGetCB(cb++); + if (chaincb < 0) + SOFT_ERROR(PI_CHAIN_TOO_BIG, "chain is too long (%d)", cb); + + p = rawWaveCBAdr(chaincb); + + repeat = waveCbPOadr(chainGetCB(loop)); + + /* Need to check next cb as well. */ + + chaincb = chainGetCB(cb); + + if (chaincb < 0) + SOFT_ERROR(PI_CHAIN_TOO_BIG, "chain is too long (%d)", cb); + + next = waveCbPOadr(chainGetCB(cb)); + + /* dummy src and dest */ + p->info = NORMAL_DMA; + p->src = (uint32_t) (&dmaOBus[0]->periphData); + p->dst = (uint32_t) (&dmaOBus[0]->periphData); + p->length = 4; + p->next = waveCbPOadr(chainGetCntCB(counters)); + + chainMakeCounter(counters, blklen, blocks, + cycles-1, repeat, next); + + counters++; + } + loop = -1; + } + else if (cmd == 2) /* delay us */ + { + if ((i+4) > bufSize) + SOFT_ERROR(PI_BAD_CHAIN_CMD, + "incomplete chain command (at %d)", i); + + cycles = ((unsigned)buf[i+3] << 8) + (unsigned)buf[i+2]; + + i += 4; + + if (cycles > PI_MAX_WAVE_DELAY) + SOFT_ERROR(PI_BAD_CHAIN_DELAY, + "bad chain delay micros (%d)", cycles); + + if (cycles) + { + chaincb = chainGetCB(cb++); + + if (chaincb < 0) + SOFT_ERROR(PI_CHAIN_TOO_BIG, "chain is too long (%d)", cb); + + p = rawWaveCBAdr(chaincb); + + /* use the secondary clock */ + + if (gpioCfg.clockPeriph != PI_CLOCK_PCM) + { + p->info = NORMAL_DMA | TIMED_DMA(2); + p->dst = PCM_TIMER; + } + else + { + p->info = NORMAL_DMA | TIMED_DMA(5); + p->dst = PWM_TIMER; + } + + p->src = (uint32_t) (&dmaOBus[0]->periphData); + p->length = 4 * cycles / PI_WF_MICROS; + p->next = waveCbPOadr(chainGetCB(cb)); + } + } + else + SOFT_ERROR(PI_BAD_CHAIN_CMD, + "unknown chain command (255 %d)", cmd); } - else if (wid >= waveOutCount) + else if ((wid >= waveOutCount) || waveInfo[wid].deleted) SOFT_ERROR(PI_BAD_WAVE_ID, "undefined wave (%d)", wid); else { - if (used[wid] == 255) - { - used[wid] = counters; + chaincb = chainGetCB(cb++); - if (firstCB < 0) firstCB = waveInfo[wid].botCB; + if (chaincb < 0) + SOFT_ERROR(PI_CHAIN_TOO_BIG, "chain is too long (%d)", cb); - if (lastCB >= 0) - { - p = rawWaveCBAdr(lastCB); + p = rawWaveCBAdr(chaincb); - p->next = waveCbPOadr(1+waveInfo[wid].botCB); - } - lastCB = waveInfo[wid].topCB; - } - else SOFT_ERROR(PI_REUSED_WID, - "wave already used in chain (%d)", wid); + chaincb = chainGetCB(cb); + + if (chaincb < 0) + SOFT_ERROR(PI_CHAIN_TOO_BIG, "chain is too long (%d)", cb); + + chainSetVal(cb-1, waveCbPOadr(chaincb)); + + /* patch next of wid topCB to next cb */ + + p->info = NORMAL_DMA; + p->src = chainGetValPadr(cb-1); /* this next */ + p->dst = waveCbPOadr(waveInfo[wid].topCB) + 20; /* wid next */ + p->length = 4; + p->next = waveCbPOadr(waveInfo[wid].botCB+1); + + i += 1; } - i++; } - if (firstCB >= 0) - { - if (lastCB >= 0) - { - p = rawWaveCBAdr(lastCB); + chaincb = chainGetCB(cb++); - p->next = 0; - } + if (chaincb < 0) + SOFT_ERROR(PI_CHAIN_TOO_BIG, "chain is too long (%d)", cb); - initDMAgo((uint32_t *)dmaOut, waveCbPOadr(firstCB)); - } + p = rawWaveCBAdr(chaincb); + + p->info = NORMAL_DMA; + p->src = (uint32_t) (&dmaOBus[0]->periphData); + p->dst = (uint32_t) (&dmaOBus[0]->periphData); + p->length = 4; + p->next = 0; + + initDMAgo((uint32_t *)dmaOut, waveCbPOadr(chainGetCB(0))); return 0; } diff --git a/pigpio.h b/pigpio.h index f5f12a6..a13d3be 100644 --- a/pigpio.h +++ b/pigpio.h @@ -31,7 +31,7 @@ For more information, please refer to #include #include -#define PIGPIO_VERSION 34 +#define PIGPIO_VERSION 35 /*TEXT @@ -197,7 +197,7 @@ gpioWaveAddGeneric Adds a series of pulses to the waveform gpioWaveAddSerial Adds serial data to the waveform gpioWaveCreate Creates a waveform from added data -gpioWaveDelete Deletes one or more waveforms +gpioWaveDelete Deletes a waveform gpioWaveTxSend Transmits a waveform @@ -218,8 +218,6 @@ gpioWaveGetCbs Length in control blocks of the current waveform gpioWaveGetHighCbs Length of longest waveform so far gpioWaveGetMaxCbs Absolute maximum allowed control blocks -gpioWaveTxStart Creates/transmits a waveform (DEPRECATED) - I2C i2cOpen Opens an I2C device @@ -383,12 +381,31 @@ typedef struct uint32_t flags; } rawWave_t; +/* +CBs are used in order from the lowest numbered CB up to +the maximum NUM_WAVE_CBS. + +OOLS are used from the bottom climbing up and from +the top climbing down. + +The gpio on and off settings climb up from the bottom (botOOL/numBOOL). + +The level and tick read values are stored in descending locations +from the top (topOOL/numTOOL). +*/ + typedef struct { uint16_t botCB; /* first CB used by wave */ uint16_t topCB; /* last CB used by wave */ - uint16_t botOOL; /* last OOL used by wave */ - uint16_t topOOL; /* first OOL used by wave */ + uint16_t botOOL; /* first bottom OOL used by wave */ + /* botOOL to botOOL + numBOOL -1 are in use */ + uint16_t topOOL; /* last top OOL used by wave */ + /* topOOL - numTOOL to topOOL are in use.*/ + uint16_t deleted; + uint16_t numCB; + uint16_t numBOOL; + uint16_t numTOOL; } rawWaveInfo_t; typedef struct @@ -549,10 +566,12 @@ typedef void *(gpioThreadFunc_t) (void *); #define PI_WAVE_MAX_MICROS (30 * 60 * 1000000) /* half an hour */ -#define PI_MAX_WAVES 250 -//#define PI_MAX_WAVE_CYCLES 537824 -#define PI_MAX_WAVE_CYCLES 16777216 -#define PI_WAVE_COUNTERS 5 +#define PI_MAX_WAVES 250 + +#define PI_MAX_WAVE_CYCLES 65535 +#define PI_MAX_WAVE_DELAY 65535 + +#define PI_WAVE_COUNT_PAGES 10 /* wave tx mode */ @@ -1511,8 +1530,9 @@ D*/ int gpioWaveCreate(void); /*D This function creates a waveform from the data provided by the prior -calls to the [*gpioWaveAdd**] functions. Upon success a positive wave id -is returned. +calls to the [*gpioWaveAdd**] functions. Upon success a wave id +greater than or equal to 0 is returned, otherwise PI_EMPTY_WAVEFORM, +PI_TOO_MANY_CBS, PI_TOO_MANY_OOL, or PI_NO_WAVEFORM_ID. The data provided by the [*gpioWaveAdd**] functions is consumed by this function. @@ -1564,8 +1584,7 @@ D*/ /*F*/ int gpioWaveDelete(unsigned wave_id); /*D -This function deletes all created waveforms with ids greater than or -equal to wave_id. +This function deletes the waveform with id wave_id. . . wave_id: >=0, as returned by [*gpioWaveCreate*] @@ -1577,26 +1596,6 @@ Returns 0 if OK, otherwise PI_BAD_WAVE_ID. D*/ -/*F*/ -int gpioWaveTxStart(unsigned wave_mode); /* DEPRECATED */ -/*D -This function creates and then transmits a waveform. The mode -determines whether the waveform is sent once or cycles endlessly. - -NOTE: Any hardware PWM started by [*gpioHardwarePWM*] will be cancelled. - -. . -wave_mode: 0 (PI_WAVE_MODE_ONE_SHOT), 1 (PI_WAVE_MODE_REPEAT) -. . - -This function is deprecated and should no longer be used. Use -[*gpioWaveCreate*] and [*gpioWaveTxSend*] instead. - -Returns the number of DMA control blocks in the waveform if OK, -otherwise PI_BAD_WAVE_MODE. -D*/ - - /*F*/ int gpioWaveTxSend(unsigned wave_id, unsigned wave_mode); /*D @@ -1623,7 +1622,7 @@ This function transmits a chain of waveforms. NOTE: Any hardware PWM started by [*gpioHardwarePWM*] will be cancelled. The waves to be transmitted are specified by the contents of buf -which contains an ordered list of wave_ids and optional command +which contains an ordered list of [*wave_id*]s and optional command codes and related data. . . @@ -1631,51 +1630,81 @@ codes and related data. bufSize: the number of bytes in buf . . -Returns 0 if OK, otherwise PI_BAD_REPEAT_CNT, PI_BAD_REPEAT_WID, -PI_BAD_CHAIN_CMD, PI_TOO_MANY_COUNTS, or PI_BAD_WAVE_ID. +Returns 0 if OK, otherwise PI_CHAIN_NESTING, PI_CHAIN_LOOP_CNT, PI_BAD_CHAIN_LOOP, PI_BAD_CHAIN_CMD, PI_CHAIN_COUNTER, +PI_BAD_CHAIN_DELAY, PI_CHAIN_TOO_BIG, or PI_BAD_WAVE_ID. -Each wave is transmitted in the order specified. A wave may only -occur once per chain. Waves may be transmitted multiple times by -using the repeat command. The repeat command specifies a wave id -and a count. The wave id must occur earlier in the chain. All the -waves between wave id and the repeat command are transmitted count -times. +Each wave is transmitted in the order specified. A wave may +occur multiple times per chain. -Repeat commands may not be nested. The minimum repeat count is 2. -A maximum of 5 repeat commands is supported per chain. +A blocks of waves may be transmitted multiple times by using +the loop commands. The block is bracketed by loop start and +end commands. Loops may be nested. + +Delays between waves may be added with the delay command. The following command codes are supported: -Name @ Cmd & Data @ Meaning -Repeat @ 255 wid C0 C1 C2 @ Repeat from wid count times -count = C0 + C1*256 + C2*65536 +Name @ Cmd & Data @ Meaning +Loop Start @ 255 0 @ Identify start of a wave block +Loop Repeat @ 255 1 x y @ loop x + y*256 times +Delay @ 255 2 x y @ delay x + y*256 microseconds + +The code is currently dimensioned to support a chain with roughly +600 entries and 20 loop counters. ... -The following examples assume that waves with ids 0 to 12 exist. +#include +#include -// 0 255 0 57 0 0 (repeat 0 57 times) -status = gpioWaveChain((char []){0, 255, 0, 57, 0, 0}, 6); +#define WAVES 5 +#define GPIO 4 -// 0 1 255 0 0 2 0 (repeat 0+1 512 times) -status = gpioWaveChain((char []){0, 1, 255, 0, 0, 2, 0}, 7); +int main(int argc, char *argv[]) +{ + int i, wid[WAVES]; -// 0 1 255 1 0 0 1 (transmit 0, repeat 1 65536 times) -status = gpioWaveChain((char []){0, 1, 255, 1, 0, 0, 1}, 7); + if (gpioInitialise()<0) return -1; -// 0 1 2 3 255 2 13 0 0 (transmit 0+1, repeat 2+3 13 times) -status = gpioWaveChain( - (char []){0, 1, 2, 3, 255, 2, 13, 0, 0}, 9); + gpioSetMode(GPIO, PI_OUTPUT); -// The following repeats 5 65793 times, transmits 6, -// repeats 7+8 514 times, transmits 12, -// repeats 9+11+10 197121 times. -// 5 255 5 1 1 1 6 7 8 255 7 2 2 0 12 9 11 10 255 9 1 2 3 -char chain[] = { - 5, 255, 5, 1, 1, 1, - 6, 7, 8, 255, 7, 2, 2, 0, - 12, 9, 11, 10, 255, 9, 1, 2, 3}; + printf("start piscope, press return\n"); getchar(); -status = gpioWaveChain(chain, sizeof(chain)); + for (i=0; i=0) if OK. + Returns a wave id (>=0) if OK, otherwise PI_EMPTY_WAVEFORM, + PI_TOO_MANY_CBS, PI_TOO_MANY_OOL, or PI_NO_WAVEFORM_ID. The data provided by the [*wave_add_**] functions is consumed by this function. @@ -1864,40 +1867,33 @@ class pi(): def wave_delete(self, wave_id): """ - Deletes all created waveforms with ids greater than or equal - to wave_id. + This function deletes the waveform with id wave_id. wave_id:= >=0 (as returned by a prior call to [*wave_create*]). Wave ids are allocated in order, 0, 1, 2, etc. ... - pi.wave_delete(6) # delete all waves with id 6 or greater + pi.wave_delete(6) # delete waveform with id 6 - pi.wave_delete(0) # delete all waves + pi.wave_delete(0) # delete waveform with id 0 ... """ return _u2i(_pigpio_command(self.sl, _PI_CMD_WVDEL, wave_id, 0)) def wave_tx_start(self): # DEPRECATED """ - This function is deprecated and will be removed. + This function is deprecated and has been removed. Use [*wave_create*]/[*wave_send_**] instead. - - NOTE: Any hardware PWM started by [*hardware_PWM*] will - be cancelled. """ return _u2i(_pigpio_command(self.sl, _PI_CMD_WVGO, 0, 0)) def wave_tx_repeat(self): # DEPRECATED """ - This function is deprecated and will be removed. + This function is deprecated and has beeen removed. Use [*wave_create*]/[*wave_send_**] instead. - - NOTE: Any hardware PWM started by [*hardware_PWM*] will - be cancelled. """ return _u2i(_pigpio_command(self.sl, _PI_CMD_WVGOR, 0, 0)) @@ -1975,58 +1971,84 @@ class pi(): """ This function transmits a chain of waveforms. - NOTE: Any hardware PWM started by [*hardware_PWM*] will - be cancelled. + NOTE: Any hardware PWM started by [*hardware_PWM*] + will be cancelled. - The waves to be transmitted are specified by the contents of - data which contains an ordered list of wave_ids and optional - command codes and related data. + The waves to be transmitted are specified by the contents + of data which contains an ordered list of [*wave_id*]s + and optional command codes and related data. - data:= contains the wave_ids and optional command codes + Returns 0 if OK, otherwise PI_CHAIN_NESTING, + PI_CHAIN_LOOP_CNT, PI_BAD_CHAIN_LOOP, PI_BAD_CHAIN_CMD, + PI_CHAIN_COUNTER, PI_BAD_CHAIN_DELAY, PI_CHAIN_TOO_BIG, + or PI_BAD_WAVE_ID. - Returns 0 if OK, otherwise PI_BAD_REPEAT_CNT, PI_BAD_REPEAT_WID, - PI_BAD_CHAIN_CMD, PI_TOO_MANY_COUNTS, or PI_BAD_WAVE_ID. + Each wave is transmitted in the order specified. A wave + may occur multiple times per chain. - Each wave is transmitted in the order specified. A wave may - only occur once per chain. Waves may be transmitted multiple - times by using the repeat command. The repeat command - specifies a wave id and a count. The wave id must occur - earlier in the chain. All the waves between wave id and the - repeat command are transmitted count times. + A blocks of waves may be transmitted multiple times by + using the loop commands. The block is bracketed by loop + start and end commands. Loops may be nested. - Repeat commands may not be nested. The minimum repeat - count is 2. A maximum of 5 repeat commands is supported - per chain. + Delays between waves may be added with the delay command. The following command codes are supported: - Name @ Cmd & Data @ Meaning - Repeat @ 255 wid C0 C1 C2 @ Repeat from wid count times - count = C0 + C1*256 + C2*65536 + Name @ Cmd & Data @ Meaning + Loop Start @ 255 0 @ Identify start of a wave block + Loop Repeat @ 255 1 x y @ loop x + y*256 times + Delay @ 255 2 x y @ delay x + y*256 microseconds + + The code is currently dimensioned to support a chain with + roughly 600 entries and 20 loop counters. ... - The following examples assume that waves with ids 0 to 12 exist. + #!/usr/bin/env python - # 0 255 0 57 0 0 (repeat 0 57 times) - pi.wave_chain([0, 255, 0, 57, 0, 0]) + import time + import pigpio - # 0 1 255 0 0 2 0 (repeat 0+1 512 times) - pi.wave_chain([0, 1, 255, 0, 0, 2, 0]) + WAVES=5 + GPIO=4 - # 0 1 255 1 0 0 1 (transmit 0, repeat 1 65536 times) - pi.wave_chain([0, 1, 255, 1, 0, 0, 1]) + wid=[0]*WAVES - # 0 1 2 3 255 2 13 0 0 (transmit 0+1, repeat 2+3 13 times) - pi.wave_chain([0, 1, 2, 3, 255, 2, 13, 0, 0]) + pi = pigpio.pi() # Connect to local Pi. + + pi.set_mode(GPIO, pigpio.OUTPUT); + + for i in range(WAVES): + pi.wave_add_generic([ + pigpio.pulse(1< +.br +#include .br .br -// 0 255 0 57 0 0 (repeat 0 57 times) +#define WAVES 5 .br -status = wave_chain((char []){0, 255, 0, 57, 0, 0}, 6); +#define GPIO 4 .br .br -// 0 1 255 0 0 2 0 (repeat 0+1 512 times) +int main(int argc, char *argv[]) .br -status = wave_chain((char []){0, 1, 255, 0, 0, 2, 0}, 7); +{ +.br + int i, wid[WAVES]; .br .br -// 0 1 255 1 0 0 1 (transmit 0, repeat 1 65536 times) -.br -status = wave_chain((char []){0, 1, 255, 1, 0, 0, 1}, 7); + if (pigpio_start(0, 0)<0) return -1; .br .br -// 0 1 2 3 255 2 13 0 0 (transmit 0+1, repeat 2+3 13 times) -.br -status = wave_chain( -.br - (char []){0, 1, 2, 3, 255, 2, 13, 0, 0}, 9); + set_mode(GPIO, PI_OUTPUT); .br .br -// The following repeats 5 65793 times, transmits 6, + for (i=0; i */ -/* PIGPIOD_IF_VERSION 16 */ +/* PIGPIOD_IF_VERSION 17 */ #include #include diff --git a/pigpiod_if.h b/pigpiod_if.h index 5f32ffe..ae96930 100644 --- a/pigpiod_if.h +++ b/pigpiod_if.h @@ -30,7 +30,7 @@ For more information, please refer to #include "pigpio.h" -#define PIGPIOD_IF_VERSION 16 +#define PIGPIOD_IF_VERSION 17 /*TEXT @@ -204,9 +204,6 @@ wave_get_cbs Length in cbs of the current waveform wave_get_high_cbs Length of longest waveform so far wave_get_max_cbs Absolute maximum allowed cbs -wave_tx_start Creates/transmits a waveform (DEPRECATED) -wave_tx_repeat Creates/transmits a waveform repeatedly (DEPRECATED) - I2C i2c_open Opens an I2C device @@ -914,8 +911,8 @@ int hardware_PWM(unsigned gpio, unsigned PWMfreq, uint32_t PWMduty); Starts hardware PWM on a gpio at the specified frequency and dutycycle. Frequencies above 30MHz are unlikely to work. -NOTE: Any waveform started by [*wave_send_once*], [*wave_send_repeat*], [*wave_tx_start*], [*wave_tx_repeat*], or [*wave_chain*] -will be cancelled. +NOTE: Any waveform started by [*wave_send_once*], [*wave_send_repeat*], +or [*wave_chain*] will be cancelled. This function is only valid if the pigpio main clock is PCM. The main clock defaults to PCM but may be overridden when the pigpio @@ -1081,8 +1078,9 @@ D*/ int wave_create(void); /*D This function creates a waveform from the data provided by the prior -calls to the [*wave_add_**] functions. Upon success a positive wave id -is returned. +calls to the [*wave_add_**] functions. Upon success a wave id +greater than or equal to 0 is returned, otherwise PI_EMPTY_WAVEFORM, +PI_TOO_MANY_CBS, PI_TOO_MANY_OOL, or PI_NO_WAVEFORM_ID. The data provided by the [*wave_add_**] functions is consumed by this function. @@ -1134,8 +1132,7 @@ D*/ /*F*/ int wave_delete(unsigned wave_id); /*D -This function deletes all created waveforms with ids greater than or -equal to wave_id. +This function deletes the waveform with id wave_id. . . wave_id: >=0, as returned by [*wave_create*]. @@ -1146,26 +1143,6 @@ Wave ids are allocated in order, 0, 1, 2, etc. Returns 0 if OK, otherwise PI_BAD_WAVE_ID. D*/ -/*F*/ -int wave_tx_start(void); -/*D -This function is deprecated and should no longer be used. - -Use [*wave_create*]/[*wave_send_**] instead. - -NOTE: Any hardware PWM started by [*hardware_PWM*] will be cancelled. -D*/ - -/*F*/ -int wave_tx_repeat(void); -/*D -This function is deprecated and should no longer be used. - -Use [*wave_create*]/[*wave_send_**] instead. - -NOTE: Any hardware PWM started by [*hardware_PWM*] will be cancelled. -D*/ - /*F*/ int wave_send_once(unsigned wave_id); /*D @@ -1207,7 +1184,7 @@ This function transmits a chain of waveforms. NOTE: Any hardware PWM started by [*hardware_PWM*] will be cancelled. The waves to be transmitted are specified by the contents of buf -which contains an ordered list of wave_ids and optional command +which contains an ordered list of [*wave_id*]s and optional command codes and related data. . . @@ -1215,51 +1192,77 @@ codes and related data. bufSize: the number of bytes in buf . . -Returns 0 if OK, otherwise PI_BAD_REPEAT_CNT, PI_BAD_REPEAT_WID, -PI_BAD_CHAIN_CMD, PI_TOO_MANY_COUNTS, or PI_BAD_WAVE_ID. +Returns 0 if OK, otherwise PI_CHAIN_NESTING, PI_CHAIN_LOOP_CNT, PI_BAD_CHAIN_LOOP, PI_BAD_CHAIN_CMD, PI_CHAIN_COUNTER, +PI_BAD_CHAIN_DELAY, PI_CHAIN_TOO_BIG, or PI_BAD_WAVE_ID. -Each wave is transmitted in the order specified. A wave may only -occur once per chain. Waves may be transmitted multiple times by -using the repeat command. The repeat command specifies a wave id -and a count. The wave id must occur earlier in the chain. All the -waves between wave id and the repeat command are transmitted count -times. +Each wave is transmitted in the order specified. A wave may +occur multiple times per chain. -Repeat commands may not be nested. The minimum repeat count is 2. -A maximum of 5 repeat commands is supported per chain. +A blocks of waves may be transmitted multiple times by using +the loop commands. The block is bracketed by loop start and +end commands. Loops may be nested. + +Delays between waves may be added with the delay command. The following command codes are supported: -Name @ Cmd & Data @ Meaning -Repeat @ 255 wid C0 C1 C2 @ Repeat from wid count times -count = C0 + C1*256 + C2*65536 +Name @ Cmd & Data @ Meaning +Loop Start @ 255 0 @ Identify start of a wave block +Loop Repeat @ 255 1 x y @ loop x + y*256 times +Delay @ 255 2 x y @ delay x + y*256 microseconds + +The code is currently dimensioned to support a chain with roughly +600 entries and 20 loop counters. ... -The following examples assume that waves with ids 0 to 12 exist. +#include +#include -// 0 255 0 57 0 0 (repeat 0 57 times) -status = wave_chain((char []){0, 255, 0, 57, 0, 0}, 6); +#define WAVES 5 +#define GPIO 4 -// 0 1 255 0 0 2 0 (repeat 0+1 512 times) -status = wave_chain((char []){0, 1, 255, 0, 0, 2, 0}, 7); +int main(int argc, char *argv[]) +{ + int i, wid[WAVES]; -// 0 1 255 1 0 0 1 (transmit 0, repeat 1 65536 times) -status = wave_chain((char []){0, 1, 255, 1, 0, 0, 1}, 7); + if (pigpio_start(0, 0)<0) return -1; -// 0 1 2 3 255 2 13 0 0 (transmit 0+1, repeat 2+3 13 times) -status = wave_chain( - (char []){0, 1, 2, 3, 255, 2, 13, 0, 0}, 9); + set_mode(GPIO, PI_OUTPUT); -// The following repeats 5 65793 times, transmits 6, -// repeats 7+8 514 times, transmits 12, -// repeats 9+11+10 197121 times. -// 5 255 5 1 1 1 6 7 8 255 7 2 2 0 12 9 11 10 255 9 1 2 3 -char chain[] = { - 5, 255, 5, 1, 1, 1, - 6, 7, 8, 255, 7, 2, 2, 0, - 12, 9, 11, 10, 255, 9, 1, 2, 3}; + for (i=0; i/dev/pigpio read -t 1 s /dev/pigpio +echo "wvcre" >/dev/pigpio +read -t 1 w /dev/pigpio read -t 1 s /dev/pigpio read -t 1 s /dev/pigpio +echo "wvcre" >/dev/pigpio +read -t 1 w /dev/pigpio read -t 1 s /dev/pigpio read -t 1 s /dev/pigpio read -t 1 s /dev/pigpio +echo "wvtxr $w" >/dev/pigpio read -t 1 s /dev/pigpio read -t 1 s