mirror of
https://github.com/clockworkpi/PicoCalc.git
synced 2025-12-12 10:18:54 +01:00
3996 lines
167 KiB
C
3996 lines
167 KiB
C
/***********************************************************************************************************************
|
|
PicoMite MMBasic
|
|
|
|
External.c
|
|
|
|
<COPYRIGHT HOLDERS> Geoff Graham, Peter Mather
|
|
Copyright (c) 2021, <COPYRIGHT HOLDERS> All rights reserved.
|
|
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
|
in the documentation and/or other materials provided with the distribution.
|
|
3. The name MMBasic be used when referring to the interpreter in any documentation and promotional material and the original copyright message be displayed
|
|
on the console at startup (additional copyright messages may be added).
|
|
4. All advertising materials mentioning features or use of this software must display the following acknowledgement: This product includes software developed
|
|
by the <copyright holder>.
|
|
5. Neither the name of the <copyright holder> nor the names of its contributors may be used to endorse or promote products derived from this software
|
|
without specific prior written permission.
|
|
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDERS> AS IS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDERS> BE LIABLE FOR ANY DIRECT,
|
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
************************************************************************************************************************/#include "MMBasic_Includes.h"
|
|
/**
|
|
* @file External.c
|
|
* @author Geoff Graham, Peter Mather
|
|
* @brief Source for I/O MMBasic commands and functions
|
|
*/
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
#include "Hardware_Includes.h"
|
|
#include "hardware/watchdog.h"
|
|
#include "pico/stdlib.h"
|
|
#include "hardware/clocks.h"
|
|
#include "hardware/pwm.h"
|
|
//#include "hardware/gpio.h"
|
|
#include "hardware/adc.h"
|
|
#include "hardware/structs/systick.h"
|
|
#include "hardware/structs/pwm.h"
|
|
#include "hardware/structs/pads_bank0.h"
|
|
#include "hardware/structs/adc.h"
|
|
#include "hardware/dma.h"
|
|
#include <hardware/structs/ioqspi.h>
|
|
#include <hardware/sync.h>
|
|
#define ANA_AVERAGE 10
|
|
#define ANA_DISCARD 2
|
|
|
|
extern MMFLOAT FDiv(MMFLOAT a, MMFLOAT b);
|
|
extern MMFLOAT FMul(MMFLOAT a, MMFLOAT b);
|
|
extern MMFLOAT FSub(MMFLOAT a, MMFLOAT b);
|
|
const char *PinFunction[] = {
|
|
"OFF",
|
|
"AIN",
|
|
"DIN",
|
|
"FIN",
|
|
"PER",
|
|
"CIN",
|
|
"INTH",
|
|
"INTL",
|
|
"DOUT",
|
|
"HEARTBEAT",
|
|
"INTB",
|
|
"UART0TX",
|
|
"UART0RX",
|
|
"UART1TX",
|
|
"UART1RX",
|
|
"I2C0SDA",
|
|
"I2C0SCL",
|
|
"I2C1SDA",
|
|
"I2C1SCL",
|
|
"SPI0RX",
|
|
"SPI0TX",
|
|
"SPI0SCK",
|
|
"SPI1RX",
|
|
"SPI1TX",
|
|
"SPI1SCK",
|
|
"IR",
|
|
"INT1",
|
|
"INT2",
|
|
"INT3",
|
|
"INT4",
|
|
"PWM0A",
|
|
"PWM0B",
|
|
"PWM1A",
|
|
"PWM1B",
|
|
"PWM2A",
|
|
"PWM2B",
|
|
"PWM3A",
|
|
"PWM3B",
|
|
"PWM4A",
|
|
"PWM4B",
|
|
"PWM5A",
|
|
"PWM5B",
|
|
"PWM6A",
|
|
"PWM6B",
|
|
"PWM7A",
|
|
"PWM7B",
|
|
"ADCRAW",
|
|
#ifdef rp2350
|
|
"PWM8A",
|
|
"PWM8B",
|
|
"PWM9A",
|
|
"PWM9B",
|
|
"PWM10A",
|
|
"PWM10B",
|
|
"PWM11A",
|
|
"PWM11B",
|
|
#endif
|
|
"PIO0",
|
|
#ifdef rp2350
|
|
"PIO1",
|
|
"PIO2",
|
|
"FFIN"
|
|
#else
|
|
"PIO1"
|
|
#endif
|
|
};
|
|
;
|
|
|
|
volatile int ExtCurrentConfig[NBRPINS + 1];
|
|
volatile int INT1Value, INT1InitTimer, INT1Timer;
|
|
volatile int INT2Value, INT2InitTimer, INT2Timer;
|
|
volatile int INT3Value, INT3InitTimer, INT3Timer;
|
|
volatile int INT4Value, INT4InitTimer, INT4Timer;
|
|
volatile int64_t INT1Count,INT2Count,INT3Count, INT4Count;
|
|
uint64_t uSecoffset=0;
|
|
uint32_t pinmask=0;
|
|
volatile uint64_t IRoffset=0;
|
|
void *IrDev, *IrCmd;
|
|
volatile char IrVarType;
|
|
volatile char IrState, IrGotMsg;
|
|
int IrBits, IrCount;
|
|
unsigned char *IrInterrupt;
|
|
int last_adc=99;
|
|
volatile int CallBackEnabled=0;
|
|
uint8_t IRpin=99;
|
|
uint8_t PWM0Apin=99;
|
|
uint8_t PWM1Apin=99;
|
|
uint8_t PWM2Apin=99;
|
|
uint8_t PWM3Apin=99;
|
|
uint8_t PWM4Apin=99;
|
|
uint8_t PWM5Apin=99;
|
|
uint8_t PWM6Apin=99;
|
|
uint8_t PWM7Apin=99;
|
|
#ifdef rp2350
|
|
uint8_t PWM8Apin=99;
|
|
uint8_t PWM9Apin=99;
|
|
uint8_t PWM10Apin=99;
|
|
uint8_t PWM11Apin=99;
|
|
#endif
|
|
uint8_t PWM0Bpin=99;
|
|
uint8_t PWM1Bpin=99;
|
|
uint8_t PWM2Bpin=99;
|
|
uint8_t PWM3Bpin=99;
|
|
uint8_t PWM4Bpin=99;
|
|
uint8_t PWM5Bpin=99;
|
|
uint8_t PWM6Bpin=99;
|
|
uint8_t PWM7Bpin=99;
|
|
#ifdef rp2350
|
|
uint8_t PWM8Bpin=99;
|
|
uint8_t PWM9Bpin=99;
|
|
uint8_t PWM10Bpin=99;
|
|
uint8_t PWM11Bpin=99;
|
|
#endif
|
|
uint8_t UART1RXpin=99;
|
|
uint8_t UART1TXpin=99;
|
|
uint8_t UART0TXpin=99;
|
|
uint8_t UART0RXpin=99;
|
|
uint8_t SPI1TXpin=99;
|
|
uint8_t SPI1RXpin=99;
|
|
uint8_t SPI1SCKpin=99;
|
|
uint8_t SPI0TXpin=99;
|
|
uint8_t SPI0RXpin=99;
|
|
uint8_t SPI0SCKpin=99;
|
|
uint8_t I2C1SDApin=99;
|
|
uint8_t I2C1SCLpin=99;
|
|
uint8_t I2C0SDApin=99;
|
|
uint8_t I2C0SCLpin=99;
|
|
uint8_t slice0=0,slice1=0,slice2=0,slice3=0,slice4=0,slice5=0,slice6=0,slice7=0;
|
|
#ifdef rp2350
|
|
uint8_t slice8=0,slice9=0,slice10=0,slice11=0;
|
|
bool fast_timer_active=false;
|
|
volatile uint64_t INT5Count, INT5Value, INT5InitTimer, INT5Timer;
|
|
#endif
|
|
bool dmarunning=false;
|
|
bool ADCDualBuffering=false;
|
|
uint32_t ADCmax=0;
|
|
int ADCopen=0;
|
|
char *ADCInterrupt;
|
|
volatile MMFLOAT * volatile a1float=NULL, * volatile a2float=NULL, * volatile a3float=NULL, * volatile a4float=NULL;
|
|
volatile int ADCpos=0;
|
|
float frequency;
|
|
uint32_t ADC_dma_chan=ADC_DMA;
|
|
uint32_t ADC_dma_chan2=ADC_DMA2;
|
|
short *ADCbuffer=NULL;
|
|
void PWMoff(int slice);
|
|
volatile uint8_t *adcint=NULL;
|
|
uint8_t *adcint1=NULL;
|
|
uint8_t *adcint2=NULL;
|
|
MMFLOAT ADCscale[4], ADCbottom[4];
|
|
extern void mouse0close(void);
|
|
//Vector to CFunction routine called every command (ie, from the BASIC interrupt checker)
|
|
|
|
uint64_t readusclock(void){
|
|
return time_us_64()-uSecoffset;
|
|
}
|
|
void writeusclock(uint64_t timeset){
|
|
uSecoffset=time_us_64()-(uint64_t)timeset;
|
|
}
|
|
uint64_t readIRclock(void){
|
|
return time_us_64()-IRoffset;
|
|
}
|
|
void writeIRclock(uint64_t timeset){
|
|
IRoffset=time_us_64()-(uint64_t)timeset;
|
|
}
|
|
#ifdef rp2350
|
|
const uint8_t PINMAP[48]={1,2,4,5,6,7,9,10,11,12,14,15,16,17,19,20,21,22,24,25,26,27,29,41,42,43,31,32,34,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62};
|
|
int codemap(int pin){
|
|
#ifdef PICOMITEWEB
|
|
if(pin>29 || pin<0 || pin==23 || pin==24 || pin==25 || pin==29) error("Invalid GPIO");
|
|
#else
|
|
if(pin>(rp2350a? 29:47) || pin<0) error("Invalid GPIO");
|
|
#endif
|
|
return (int)PINMAP[pin];
|
|
}
|
|
#else
|
|
const uint8_t PINMAP[30]={1,2,4,5,6,7,9,10,11,12,14,15,16,17,19,20,21,22,24,25,26,27,29,41,42,43,31,32,34,44};
|
|
int codemap(int pin){
|
|
#ifdef PICOMITEWEB
|
|
if(pin>29 || pin<0 || pin==23 || pin==24 || pin==25 || pin==29) error("Invalid GPIO");
|
|
#else
|
|
if(pin>29 || pin<0) error("Invalid GPIO");
|
|
#endif
|
|
return (int)PINMAP[pin];
|
|
}
|
|
#endif
|
|
int codecheck(unsigned char *line){
|
|
if((line[0]=='G' || line[0]=='g') && (line[1]=='P' || line[1]=='p')){
|
|
line+=2;
|
|
if(isnamestart(*line) || *line=='.') return 1;
|
|
|
|
if(isdigit(*line) && !isnamechar(line[1])) {
|
|
return 0;
|
|
}
|
|
line++;
|
|
|
|
if(!(isdigit(*line))) return 2;
|
|
line++;
|
|
if(isnamechar(*line)) return 3;
|
|
} else return 4;
|
|
return 0;
|
|
}
|
|
#ifdef rp2350
|
|
void __not_in_flash_func(on_pwm_wrap_1)(void) {
|
|
pwm_clear_irq(0);
|
|
INT5Count++;
|
|
}
|
|
|
|
#endif
|
|
|
|
void SoftReset(void){
|
|
_excep_code = SOFT_RESET;
|
|
#ifdef USBKEYBOARD
|
|
USBenabled=false;
|
|
uSec(50000); //wait for outstanding requests to complete
|
|
#endif
|
|
watchdog_enable(1, 1);
|
|
while(1);
|
|
}
|
|
#ifdef rp2350
|
|
void __not_in_flash_func(PinSetBit)(int pin, unsigned int offset) {
|
|
#else
|
|
#if defined(PICOMITEVGA) || defined(PICOMITEWEB)
|
|
void PinSetBit(int pin, unsigned int offset) {
|
|
#else
|
|
void __not_in_flash_func(PinSetBit)(int pin, unsigned int offset) {
|
|
#endif
|
|
#endif
|
|
switch (offset){
|
|
case LATCLR:
|
|
gpio_set_pulls(PinDef[pin].GPno,false,false);
|
|
gpio_pull_down(PinDef[pin].GPno);
|
|
gpio_put(PinDef[pin].GPno,GPIO_PIN_RESET);
|
|
return;
|
|
case LATSET:
|
|
gpio_set_pulls(PinDef[pin].GPno,false,false);
|
|
gpio_pull_up(PinDef[pin].GPno);
|
|
gpio_put(PinDef[pin].GPno,GPIO_PIN_SET);
|
|
return;
|
|
case LATINV:
|
|
gpio_xor_mask64(1<<PinDef[pin].GPno);
|
|
return;
|
|
case TRISSET:
|
|
gpio_set_dir(PinDef[pin].GPno, GPIO_IN);
|
|
gpio_set_input_enabled(PinDef[pin].GPno, true);
|
|
uSec(2);
|
|
return;
|
|
case TRISCLR:
|
|
gpio_set_dir(PinDef[pin].GPno, GPIO_OUT);
|
|
gpio_set_input_enabled(PinDef[pin].GPno, false);
|
|
gpio_set_drive_strength (PinDef[pin].GPno, GPIO_DRIVE_STRENGTH_8MA);
|
|
uSec(2);
|
|
return;
|
|
case CNPUSET:
|
|
gpio_set_pulls(PinDef[pin].GPno,true,false);
|
|
return;
|
|
case CNPDSET:
|
|
gpio_set_pulls(PinDef[pin].GPno,false,true);
|
|
return;
|
|
case CNPUCLR:
|
|
case CNPDCLR:
|
|
gpio_set_pulls(PinDef[pin].GPno,false,false);
|
|
return;
|
|
case ODCCLR:
|
|
gpio_set_dir(PinDef[pin].GPno, GPIO_OUT);
|
|
gpio_put(PinDef[pin].GPno,GPIO_PIN_RESET);
|
|
uSec(2);
|
|
return;
|
|
case ODCSET:
|
|
gpio_set_pulls(PinDef[pin].GPno,true,false);
|
|
gpio_set_dir(PinDef[pin].GPno, GPIO_IN);
|
|
uSec(2);
|
|
return;
|
|
case ANSELCLR:
|
|
gpio_set_function(PinDef[pin].GPno, GPIO_FUNC_SIO);
|
|
gpio_set_dir(PinDef[pin].GPno, GPIO_IN);
|
|
return;
|
|
case ANSELSET:
|
|
gpio_set_dir(PinDef[pin].GPno, GPIO_IN);
|
|
gpio_disable_pulls(PinDef[pin].GPno);
|
|
gpio_set_input_enabled(PinDef[pin].GPno, false);
|
|
adc_select_input(PinDef[pin].ADCpin);
|
|
return;
|
|
default: error("Unknown PinSetBit command");
|
|
}
|
|
}
|
|
|
|
int IsInvalidPin(int pin) {
|
|
#ifdef rp2350
|
|
#ifdef PICOMITEWEB
|
|
if(pin < 1 || pin > NBRPINS) return true;
|
|
#else
|
|
if(pin < 1 || pin > (rp2350a ? 44: NBRPINS)) return true;
|
|
#endif
|
|
#else
|
|
if(pin < 1 || pin > NBRPINS) return true;
|
|
#endif
|
|
if(PinDef[pin].mode & UNUSED) return true;
|
|
return false;
|
|
}
|
|
#ifdef PICOMITEWEB
|
|
void ExtSet(int pin, int val){
|
|
#else
|
|
#ifndef rp2350
|
|
#ifdef PICOMITEVGA
|
|
void ExtSet(int pin, int val){
|
|
#else
|
|
void __not_in_flash_func(ExtSet)(int pin, int val){
|
|
#endif
|
|
#else
|
|
void __not_in_flash_func(ExtSet)(int pin, int val){
|
|
#endif
|
|
#endif
|
|
|
|
if(ExtCurrentConfig[pin] == EXT_NOT_CONFIG || ExtCurrentConfig[pin] == EXT_DIG_OUT/* || ExtCurrentConfig[pin] == EXT_OC_OUT*/) {
|
|
PinSetBit(pin, val ? LATSET : LATCLR);
|
|
if(ExtCurrentConfig[pin] == EXT_NOT_CONFIG){
|
|
pinmask|=(1<<PinDef[pin].GPno);
|
|
if(val)pinmask|=(1<<PinDef[pin].GPno);
|
|
else pinmask &= (~(1<<PinDef[pin].GPno));
|
|
gpio_set_input_enabled(PinDef[pin].GPno,false);
|
|
last_adc=99;
|
|
}
|
|
// INTEnableInterrupts();
|
|
}
|
|
else if(ExtCurrentConfig[pin] == EXT_CNT_IN){ //allow the user to zero the count
|
|
if(pin == Option.INT1pin) INT1Count=val;
|
|
if(pin == Option.INT2pin) INT2Count=val;
|
|
if(pin == Option.INT3pin) INT3Count=val;
|
|
if(pin == Option.INT4pin) INT4Count=val;
|
|
}
|
|
else
|
|
error("Pin %/| is not an output",pin,pin);
|
|
}
|
|
/* @endcond */
|
|
#if defined(PICOMITEVGA) && !defined(rp2350)
|
|
void cmd_sync(void){
|
|
#else
|
|
void __not_in_flash_func(cmd_sync)(void){
|
|
#endif
|
|
uint64_t i;
|
|
static uint64_t synctime=0,endtime=0;
|
|
getargs(&cmdline,3,(unsigned char *)",");
|
|
if(synctime && argc==0){
|
|
while(time_us_64()<endtime){
|
|
if(synctime-time_us_64()> 2000)CheckAbort();
|
|
}
|
|
endtime+=synctime;
|
|
} else {
|
|
if(argc==0)error("sync not initialised");
|
|
i=getint(argv[0],0,0x7FFFFFFFFFFFFFFF);
|
|
if(i){
|
|
if(argc==3){
|
|
if(checkstring(argv[2],(unsigned char *)"U")){
|
|
i *= 1;
|
|
} else if(checkstring(argv[2],(unsigned char *)"M")){
|
|
i *= 1000;
|
|
} else if(checkstring(argv[2],(unsigned char *)"S")){
|
|
i *= 1000000;
|
|
}
|
|
}
|
|
synctime=i;
|
|
endtime=time_us_64()+synctime;
|
|
} else {
|
|
synctime=endtime=0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// this is invoked as a command (ie, pin(3) = 1)
|
|
// first get the argument then step over the closing bracket. Search through the rest of the command line looking
|
|
// for the equals sign and step over it, evaluate the rest of the command and set the pin accordingly
|
|
void cmd_pin(void) {
|
|
int pin, value;
|
|
unsigned char code;
|
|
if(!(code=codecheck(cmdline)))cmdline+=2;
|
|
pin = getinteger(cmdline);
|
|
if(!code)pin=codemap(pin);
|
|
if(IsInvalidPin(pin)) error("Invalid pin");
|
|
while(*cmdline && tokenfunction(*cmdline) != op_equal) cmdline++;
|
|
if(!*cmdline) error("Invalid syntax");
|
|
++cmdline;
|
|
if(!*cmdline) error("Invalid syntax");
|
|
value = getinteger(cmdline);
|
|
ExtSet(pin, value);
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
void ClearPin(int pin){
|
|
if(pin==IRpin)IRpin=99;
|
|
if(pin==PWM0Apin)PWM0Apin=99;
|
|
if(pin==PWM1Apin)PWM1Apin=99;
|
|
if(pin==PWM2Apin)PWM2Apin=99;
|
|
if(pin==PWM3Apin)PWM3Apin=99;
|
|
if(pin==PWM4Apin)PWM4Apin=99;
|
|
if(pin==PWM5Apin)PWM5Apin=99;
|
|
if(pin==PWM6Apin)PWM6Apin=99;
|
|
if(pin==PWM7Apin)PWM7Apin=99;
|
|
#ifdef rp2350
|
|
if(pin==PWM8Apin)PWM8Apin=99;
|
|
if(pin==PWM9Apin)PWM9Apin=99;
|
|
if(pin==PWM10Apin)PWM10Apin=99;
|
|
if(pin==PWM11Apin)PWM11Apin=99;
|
|
#endif
|
|
if(pin==PWM0Bpin)PWM0Bpin=99;
|
|
if(pin==PWM1Bpin)PWM1Bpin=99;
|
|
if(pin==PWM2Bpin)PWM2Bpin=99;
|
|
if(pin==PWM3Bpin)PWM3Bpin=99;
|
|
if(pin==PWM4Bpin)PWM4Bpin=99;
|
|
if(pin==PWM5Bpin)PWM5Bpin=99;
|
|
if(pin==PWM6Bpin)PWM6Bpin=99;
|
|
if(pin==PWM7Bpin)PWM7Bpin=99;
|
|
#ifdef rp2350
|
|
if(pin==PWM8Bpin)PWM8Bpin=99;
|
|
if(pin==PWM9Bpin)PWM9Bpin=99;
|
|
if(pin==PWM10Bpin)PWM10Bpin=99;
|
|
if(pin==PWM11Bpin)PWM11Bpin=99;
|
|
#endif
|
|
if(pin==UART0TXpin)UART0TXpin=99;
|
|
if(pin==UART0RXpin)UART0RXpin=99;
|
|
if(pin==UART1RXpin)UART1RXpin=99;
|
|
if(pin==UART1TXpin)UART1TXpin=99;
|
|
if(pin==SPI1TXpin)SPI1TXpin=99;
|
|
if(pin==SPI1RXpin)SPI1RXpin=99;
|
|
if(pin==SPI1SCKpin)SPI1SCKpin=99;
|
|
if(pin==SPI0TXpin)SPI0TXpin=99;
|
|
if(pin==SPI0RXpin)SPI0RXpin=99;
|
|
if(pin==SPI0SCKpin)SPI0SCKpin=99;
|
|
if(pin==I2C1SDApin)I2C1SDApin=99;
|
|
if(pin==I2C1SCLpin)I2C1SCLpin=99;
|
|
if(pin==I2C0SDApin)I2C0SDApin=99;
|
|
if(pin==I2C0SCLpin)I2C0SCLpin=99;
|
|
}
|
|
/****************************************************************************************************************************
|
|
Configure an I/O pin
|
|
*****************************************************************************************************************************/
|
|
void MIPS16 ExtCfg(int pin, int cfg, int option) {
|
|
int i, tris=0, ana=0, edge;
|
|
|
|
CheckPin(pin, CP_IGNORE_INUSE | CP_IGNORE_RESERVED);
|
|
|
|
if(cfg >= EXT_DS18B20_RESERVED) {
|
|
ExtCurrentConfig[pin] |= cfg; // don't do anything except set the config type
|
|
return;
|
|
}
|
|
ClearPin(pin); //disable the link to any special functions
|
|
if(pin == Option.INT1pin) {
|
|
if(CallBackEnabled==2) gpio_set_irq_enabled_with_callback(PinDef[pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
|
else gpio_set_irq_enabled(PinDef[pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
|
CallBackEnabled &= (~2);
|
|
}
|
|
if(pin == Option.INT2pin) {
|
|
if(CallBackEnabled==4) gpio_set_irq_enabled_with_callback(PinDef[pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
|
else gpio_set_irq_enabled(PinDef[pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
|
CallBackEnabled &= (~4);
|
|
}
|
|
if(pin == Option.INT3pin) {
|
|
if(CallBackEnabled==8) gpio_set_irq_enabled_with_callback(PinDef[pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
|
else gpio_set_irq_enabled(PinDef[pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
|
CallBackEnabled &= (~8);
|
|
}
|
|
if(pin == Option.INT4pin) {
|
|
if(CallBackEnabled==16) gpio_set_irq_enabled_with_callback(PinDef[pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
|
else gpio_set_irq_enabled(PinDef[pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
|
CallBackEnabled &= (~16);
|
|
}
|
|
#ifdef rp2350
|
|
if(pin==FAST_TIMER_PIN && ExtCurrentConfig[pin]==EXT_FAST_TIMER){
|
|
slice0=0;
|
|
pwm_set_irq1_enabled(0, false);
|
|
}
|
|
#endif
|
|
|
|
|
|
// make sure any pullups/pulldowns are removed in case we are changing from a digital input
|
|
gpio_disable_pulls(PinDef[pin].GPno);
|
|
// disable ADC if we are changing from a analogue input
|
|
if(ExtCurrentConfig[pin]==EXT_ANA_IN || ExtCurrentConfig[pin]==EXT_ADCRAW )PinSetBit(pin, ANSELCLR);
|
|
|
|
for(i = 0; i < NBRINTERRUPTS; i++)
|
|
if(inttbl[i].pin == pin)
|
|
inttbl[i].pin = 0; // start off by disable a software interrupt (if set) on this pin
|
|
gpio_set_input_enabled(PinDef[pin].GPno,false);
|
|
gpio_deinit(PinDef[pin].GPno);
|
|
gpio_set_input_hysteresis_enabled(PinDef[pin].GPno,true);
|
|
if(cfg!=EXT_NOT_CONFIG)gpio_init(PinDef[pin].GPno);
|
|
switch(cfg) {
|
|
case EXT_NOT_CONFIG: tris = 1; ana = 1;
|
|
// gpio_init(PinDef[pin].GPno);
|
|
// gpio_set_input_hysteresis_enabled(PinDef[pin].GPno,true);
|
|
gpio_set_input_enabled(PinDef[pin].GPno,false);
|
|
gpio_deinit(PinDef[pin].GPno);
|
|
switch(ExtCurrentConfig[pin]){ //Disable the pin numbers used by the special function code
|
|
case EXT_IR:
|
|
IRpin=99;
|
|
break;
|
|
case EXT_PWM0A:
|
|
PWM0Apin=99;
|
|
break;
|
|
case EXT_PWM1A:
|
|
PWM1Apin=99;
|
|
break;
|
|
case EXT_PWM2A:
|
|
PWM2Apin=99;
|
|
break;
|
|
case EXT_PWM3A:
|
|
PWM3Apin=99;
|
|
break;
|
|
case EXT_PWM4A:
|
|
PWM4Apin=99;
|
|
break;
|
|
case EXT_PWM5A:
|
|
PWM5Apin=99;
|
|
break;
|
|
case EXT_PWM6A:
|
|
PWM6Apin=99;
|
|
break;
|
|
case EXT_PWM7A:
|
|
PWM7Apin=99;
|
|
break;
|
|
#ifdef rp2350
|
|
case EXT_PWM8A:
|
|
PWM8Apin=99;
|
|
break;
|
|
case EXT_PWM9A:
|
|
PWM9Apin=99;
|
|
break;
|
|
case EXT_PWM10A:
|
|
PWM10Apin=99;
|
|
break;
|
|
case EXT_PWM11A:
|
|
PWM11Apin=99;
|
|
break;
|
|
#endif
|
|
case EXT_PWM0B:
|
|
PWM0Bpin=99;
|
|
break;
|
|
case EXT_PWM1B:
|
|
PWM1Bpin=99;
|
|
break;
|
|
case EXT_PWM2B:
|
|
PWM2Bpin=99;
|
|
break;
|
|
case EXT_PWM3B:
|
|
PWM3Bpin=99;
|
|
break;
|
|
case EXT_PWM4B:
|
|
PWM4Bpin=99;
|
|
break;
|
|
case EXT_PWM5B:
|
|
PWM5Bpin=99;
|
|
break;
|
|
case EXT_PWM6B:
|
|
PWM6Bpin=99;
|
|
break;
|
|
case EXT_PWM7B:
|
|
PWM7Bpin=99;
|
|
break;
|
|
#ifdef rp2350
|
|
case EXT_PWM8B:
|
|
PWM8Bpin=99;
|
|
break;
|
|
case EXT_PWM9B:
|
|
PWM9Bpin=99;
|
|
break;
|
|
case EXT_PWM10B:
|
|
PWM10Bpin=99;
|
|
break;
|
|
case EXT_PWM11B:
|
|
PWM11Bpin=99;
|
|
break;
|
|
#endif
|
|
case EXT_UART0TX:
|
|
UART0TXpin=99;
|
|
break;
|
|
case EXT_UART0RX:
|
|
UART0RXpin=99;
|
|
break;
|
|
case EXT_UART1TX:
|
|
UART1TXpin=99;
|
|
break;
|
|
case EXT_UART1RX:
|
|
UART1RXpin=99;
|
|
break;
|
|
case EXT_I2C0SDA:
|
|
I2C0SDApin=99;
|
|
break;
|
|
case EXT_I2C0SCL:
|
|
I2C0SCLpin=99;
|
|
break;
|
|
case EXT_I2C1SDA:
|
|
I2C1SDApin=99;
|
|
break;
|
|
case EXT_I2C1SCL:
|
|
I2C1SCLpin=99;
|
|
break;
|
|
case EXT_SPI0RX:
|
|
SPI0RXpin=99;
|
|
break;
|
|
case EXT_SPI0TX:
|
|
SPI0TXpin=99;
|
|
break;
|
|
case EXT_SPI0SCK:
|
|
SPI0SCKpin=99;
|
|
break;
|
|
case EXT_SPI1RX:
|
|
SPI1RXpin=99;
|
|
break;
|
|
case EXT_SPI1TX:
|
|
SPI1TXpin=99;
|
|
break;
|
|
case EXT_SPI1SCK:
|
|
SPI1SCKpin=99;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
#ifdef rp2350
|
|
case EXT_ADCRAW:
|
|
case EXT_ANA_IN: if(!(PinDef[pin].mode & ANALOG_IN)) error("Invalid configuration");
|
|
if(pin<=44 && rp2350a==0) error("Invalid configuration");
|
|
if(pin> 44 && rp2350a) error("Invalid configuration");
|
|
tris = 1; ana = 0;
|
|
break;
|
|
#else
|
|
case EXT_ADCRAW:
|
|
case EXT_ANA_IN: if(!(PinDef[pin].mode & ANALOG_IN)) error("Invalid configuration");
|
|
tris = 1; ana = 0;
|
|
break;
|
|
#endif
|
|
case EXT_CNT_IN:
|
|
case EXT_FREQ_IN: // same as counting, so fall through
|
|
case EXT_PER_IN: // same as counting, so fall through
|
|
edge = GPIO_IRQ_EDGE_RISE;
|
|
if(cfg==EXT_CNT_IN && option==2)edge = GPIO_IRQ_EDGE_FALL;
|
|
if(cfg==EXT_CNT_IN && option>=3)edge = GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE;
|
|
if(option==1 || option==4)gpio_pull_down (PinDef[pin].GPno);
|
|
if(option==2 || option==5)gpio_pull_up (PinDef[pin].GPno);
|
|
irq_set_priority(IO_IRQ_BANK0,0);
|
|
PinSetBit(pin,TRISSET);
|
|
if(pin == Option.INT1pin) {
|
|
if(!CallBackEnabled){
|
|
gpio_set_irq_enabled_with_callback(PinDef[pin].GPno, edge , true, &gpio_callback);
|
|
CallBackEnabled=2;
|
|
} else {
|
|
gpio_set_irq_enabled(PinDef[pin].GPno, edge, true);
|
|
CallBackEnabled|=2;
|
|
}
|
|
INT1Count = INT1Value = 0;
|
|
INT1Timer = INT1InitTimer = option; // only used for frequency and period measurement
|
|
tris = 1; ana = 1;
|
|
gpio_set_input_hysteresis_enabled(PinDef[pin].GPno,true);
|
|
break;
|
|
}
|
|
if(pin == Option.INT2pin) {
|
|
if(!CallBackEnabled){
|
|
gpio_set_irq_enabled_with_callback(PinDef[pin].GPno, edge , true, &gpio_callback);
|
|
CallBackEnabled=4;
|
|
} else {
|
|
gpio_set_irq_enabled(PinDef[pin].GPno, edge, true);
|
|
CallBackEnabled|=4;
|
|
}
|
|
INT2Count = INT2Value = 0;
|
|
INT2Timer = INT2InitTimer = option; // only used for frequency and period measurement
|
|
tris = 1; ana = 1;
|
|
gpio_set_input_hysteresis_enabled(PinDef[pin].GPno,true);
|
|
break;
|
|
}
|
|
if(pin == Option.INT3pin) {
|
|
if(!CallBackEnabled){
|
|
gpio_set_irq_enabled_with_callback(PinDef[pin].GPno, edge , true, &gpio_callback);
|
|
CallBackEnabled=8;
|
|
} else {
|
|
gpio_set_irq_enabled(PinDef[pin].GPno, edge, true);
|
|
CallBackEnabled|=8;
|
|
}
|
|
INT3Count = INT3Value = 0;
|
|
INT3Timer = INT3InitTimer = option; // only used for frequency and period measurement
|
|
tris = 1; ana = 1;
|
|
gpio_set_input_hysteresis_enabled(PinDef[pin].GPno,true);
|
|
break;
|
|
}
|
|
if(pin == Option.INT4pin) {
|
|
if(!CallBackEnabled){
|
|
gpio_set_irq_enabled_with_callback(PinDef[pin].GPno, edge , true, &gpio_callback);
|
|
CallBackEnabled=16;
|
|
} else {
|
|
gpio_set_irq_enabled(PinDef[pin].GPno, edge, true);
|
|
CallBackEnabled|=16;
|
|
}
|
|
INT4Count = INT4Value = 0;
|
|
INT4Timer = INT4InitTimer = option; // only used for frequency and period measurement
|
|
tris = 1; ana = 1;
|
|
gpio_set_input_hysteresis_enabled(PinDef[pin].GPno,true);
|
|
break;
|
|
}
|
|
error("Invalid configuration"); // not an interrupt enabled pin
|
|
return;
|
|
|
|
case EXT_INT_LO: // same as digital input, so fall through
|
|
case EXT_INT_HI: // same as digital input, so fall through
|
|
case EXT_INT_BOTH: // same as digital input, so fall through
|
|
case EXT_DIG_IN: if(!(PinDef[pin].mode & DIGITAL_IN)) error("Invalid configuration");
|
|
if(option) PinSetBit(pin, option);
|
|
tris = 1; ana = 1;
|
|
gpio_set_input_hysteresis_enabled(PinDef[pin].GPno,true);
|
|
break;
|
|
|
|
case EXT_PIO0_OUT:
|
|
case EXT_PIO1_OUT:
|
|
#ifdef rp2350
|
|
case EXT_PIO2_OUT:
|
|
#endif
|
|
case EXT_DIG_OUT: if(!(PinDef[pin].mode & DIGITAL_OUT)) error("Invalid configuration");
|
|
tris = 0; ana = 1;
|
|
gpio_set_drive_strength(PinDef[pin].GPno,GPIO_DRIVE_STRENGTH_8MA);
|
|
break;
|
|
#ifndef PICOMITEWEB
|
|
case EXT_HEARTBEAT: if(!(pin=HEARTBEATpin)) error("Invalid configuration");
|
|
tris = 0; ana = 1;
|
|
break;
|
|
#endif
|
|
case EXT_UART0TX: if(!(PinDef[pin].mode & UART0TX)) error("Invalid configuration");
|
|
if((UART0TXpin!=99)) error("Already Set to pin %",UART0TXpin);
|
|
UART0TXpin=pin;
|
|
break;
|
|
case EXT_UART0RX: if(!(PinDef[pin].mode & UART0RX)) error("Invalid configuration");
|
|
if((UART0RXpin!=99)) error("Already Set to pin %",UART0RXpin);
|
|
UART0RXpin=pin;
|
|
break;
|
|
case EXT_UART1TX: if(!(PinDef[pin].mode & UART1TX)) error("Invalid configuration");
|
|
if((UART1TXpin!=99)) error("Already Set to pin %",UART1TXpin);
|
|
UART1TXpin=pin;
|
|
break;
|
|
case EXT_UART1RX: if(!(PinDef[pin].mode & UART1RX)) error("Invalid configuration");
|
|
if((UART1RXpin!=99)) error("Already Set to pin %",UART1RXpin);
|
|
UART1RXpin=pin;
|
|
break;
|
|
case EXT_SPI0TX: if(!(PinDef[pin].mode & SPI0TX)) error("Invalid configuration");
|
|
if(SPI0locked)error("SPI in use for SYSTEM SPI");
|
|
if((SPI0TXpin!=99 && SPI0TXpin!=pin)) error("Already Set to pin %",SPI0TXpin);
|
|
SPI0TXpin=pin;
|
|
break;
|
|
case EXT_SPI0RX: if(!(PinDef[pin].mode & SPI0RX)) error("Invalid configuration");
|
|
if(SPI0locked)error("SPI in use for SYSTEM SPI");
|
|
if((SPI0RXpin!=99 && SPI0RXpin!=pin)) error("Already Set to pin %",SPI0RXpin);
|
|
SPI0RXpin=pin;
|
|
break;
|
|
case EXT_SPI0SCK: if(!(PinDef[pin].mode & SPI0SCK)) error("Invalid configuration");
|
|
if(SPI0locked)error("SPI in use for SYSTEM SPI");
|
|
if((SPI0SCKpin!=99 && SPI0SCKpin!=pin)) error("Already Set to pin %",SPI0SCKpin);
|
|
SPI0SCKpin=pin;
|
|
break;
|
|
case EXT_SPI1TX: if(!(PinDef[pin].mode & SPI1TX)) error("Invalid configuration");
|
|
if(SPI1locked)error("SPI2 in use for SYSTEM SPI");
|
|
if((SPI1TXpin!=99 && SPI1TXpin!=pin)) error("Already Set to pin %",SPI1TXpin);
|
|
SPI1TXpin=pin;
|
|
break;
|
|
case EXT_SPI1RX: if(!(PinDef[pin].mode & SPI1RX)) error("Invalid configuration");
|
|
if(SPI1locked)error("SPI2 in use for SYSTEM SPI");
|
|
if((SPI1RXpin!=99 && SPI1RXpin!=pin)) error("Already Set to pin %",SPI1RXpin);
|
|
SPI1RXpin=pin;
|
|
break;
|
|
case EXT_SPI1SCK: if(!(PinDef[pin].mode & SPI1SCK)) error("Invalid configuration");
|
|
if(SPI1locked)error("SPI2 in use for SYSTEM SPI");
|
|
if((SPI1SCKpin!=99 && SPI1SCKpin!=pin)) error("Already Set to pin %",SPI1SCKpin);
|
|
SPI1SCKpin=pin;
|
|
break;
|
|
case EXT_IR: if((IRpin!=99)) error("Already Set to pin %",IRpin);
|
|
IRpin=pin;
|
|
break;
|
|
case EXT_PWM0A: if(!(PinDef[pin].mode & PWM0A)) error("Invalid configuration");
|
|
if((PWM0Apin!=99 && PWM0Apin!=pin)) error("Already Set to pin %",PWM0Apin);
|
|
PWM0Apin=pin;
|
|
break;
|
|
case EXT_PWM1A: if(!(PinDef[pin].mode & PWM1A)) error("Invalid configuration");
|
|
if((PWM1Apin!=99 && PWM1Apin!=pin)) error("Already Set to pin %",PWM1Apin);
|
|
PWM1Apin=pin;
|
|
break;
|
|
case EXT_PWM2A: if(!(PinDef[pin].mode & PWM2A)) error("Invalid configuration");
|
|
if((PWM2Apin!=99 && PWM2Apin!=pin)) error("Already Set to pin %",PWM2Apin);
|
|
PWM2Apin=pin;
|
|
gpio_set_drive_strength (PinDef[pin].GPno, GPIO_DRIVE_STRENGTH_8MA);
|
|
gpio_set_slew_rate(PinDef[pin].GPno,GPIO_SLEW_RATE_FAST);
|
|
break;
|
|
case EXT_PWM3A: if(!(PinDef[pin].mode & PWM3A)) error("Invalid configuration");
|
|
if((PWM3Apin!=99 && PWM3Apin!=pin)) error("Already Set to pin %",PWM3Apin);
|
|
PWM3Apin=pin;
|
|
break;
|
|
case EXT_PWM4A: if(!(PinDef[pin].mode & PWM4A)) error("Invalid configuration");
|
|
if((PWM4Apin!=99 && PWM4Apin!=pin)) error("Already Set to pin %",PWM4Apin);
|
|
PWM4Apin=pin;
|
|
break;
|
|
case EXT_PWM5A: if(!(PinDef[pin].mode & PWM5A)) error("Invalid configuration");
|
|
if((PWM5Apin!=99 && PWM5Apin!=pin)) error("Already Set to pin %",PWM5Apin);
|
|
PWM5Apin=pin;
|
|
break;
|
|
case EXT_PWM6A: if(!(PinDef[pin].mode & PWM6A)) error("Invalid configuration");
|
|
if((PWM6Apin!=99 && PWM6Apin!=pin)) error("Already Set to pin %",PWM6Apin);
|
|
PWM6Apin=pin;
|
|
break;
|
|
case EXT_PWM7A: if(!(PinDef[pin].mode & PWM7A)) error("Invalid configuration");
|
|
if((PWM7Apin!=99 && PWM7Apin!=pin)) error("Already Set to pin %",PWM7Apin);
|
|
PWM7Apin=pin;
|
|
break;
|
|
#ifdef rp2350
|
|
case EXT_PWM8A: if(!(PinDef[pin].mode & PWM8A) || rp2350a) error("Invalid configuration");
|
|
if((PWM8Apin!=99 && PWM8Apin!=pin)) error("Already Set to pin %",PWM8Apin);
|
|
PWM8Apin=pin;
|
|
break;
|
|
case EXT_PWM9A: if(!(PinDef[pin].mode & PWM9A) || rp2350a) error("Invalid configuration");
|
|
if((PWM9Apin!=99 && PWM9Apin!=pin)) error("Already Set to pin %",PWM9Apin);
|
|
PWM9Apin=pin;
|
|
break;
|
|
case EXT_PWM10A: if(!(PinDef[pin].mode & PWM10A) || rp2350a) error("Invalid configuration");
|
|
if((PWM10Apin!=99 && PWM10Apin!=pin)) error("Already Set to pin %",PWM10Apin);
|
|
PWM10Apin=pin;
|
|
break;
|
|
case EXT_PWM11A: if(!(PinDef[pin].mode & PWM11A) || rp2350a) error("Invalid configuration");
|
|
if((PWM11Apin!=99 && PWM11Apin!=pin)) error("Already Set to pin %",PWM11Apin);
|
|
PWM11Apin=pin;
|
|
break;
|
|
#endif
|
|
case EXT_PWM0B: if(!(PinDef[pin].mode & PWM0B)) error("Invalid configuration");
|
|
if((PWM0Bpin!=99 && PWM0Bpin!=pin)) error("Already Set to pin %",PWM0Bpin);
|
|
PWM0Bpin=pin;
|
|
break;
|
|
case EXT_PWM1B: if(!(PinDef[pin].mode & PWM1B)) error("Invalid configuration");
|
|
if((PWM1Bpin!=99 && PWM1Bpin!=pin)) error("Already Set to pin %",PWM1Bpin);
|
|
PWM1Bpin=pin;
|
|
break;
|
|
case EXT_PWM2B: if(!(PinDef[pin].mode & PWM2B)) error("Invalid configuration");
|
|
if((PWM2Bpin!=99 && PWM2Bpin!=pin)) error("Already Set to pin %",PWM2Bpin);
|
|
PWM2Bpin=pin;
|
|
break;
|
|
case EXT_PWM3B: if(!(PinDef[pin].mode & PWM3B)) error("Invalid configuration");
|
|
if((PWM3Bpin!=99 && PWM3Bpin!=pin)) error("Already Set to pin %",PWM3Bpin);
|
|
PWM3Bpin=pin;
|
|
break;
|
|
case EXT_PWM4B: if(!(PinDef[pin].mode & PWM4B)) error("Invalid configuration");
|
|
if((PWM4Bpin!=99 && PWM4Bpin!=pin)) error("Already Set to pin %",PWM4Bpin);
|
|
PWM4Bpin=pin;
|
|
break;
|
|
case EXT_PWM5B: if(!(PinDef[pin].mode & PWM5B)) error("Invalid configuration");
|
|
if((PWM5Bpin!=99 && PWM5Bpin!=pin)) error("Already Set to pin %",PWM5Bpin);
|
|
PWM5Bpin=pin;
|
|
break;
|
|
case EXT_PWM6B: if(!(PinDef[pin].mode & PWM6B)) error("Invalid configuration");
|
|
if((PWM6Bpin!=99 && PWM6Bpin!=pin)) error("Already Set to pin %",PWM6Bpin);
|
|
PWM6Bpin=pin;
|
|
break;
|
|
case EXT_PWM7B: if(!(PinDef[pin].mode & PWM7B)) error("Invalid configuration");
|
|
if((PWM7Bpin!=99 && PWM7Bpin!=pin)) error("Already Set to pin %",PWM7Bpin);
|
|
PWM7Bpin=pin;
|
|
break;
|
|
#ifdef rp2350
|
|
#ifndef PICOMITEWEB
|
|
case EXT_PWM8B: if(!(PinDef[pin].mode & PWM8B) || rp2350a) error("Invalid configuration");
|
|
if((PWM8Bpin!=99 && PWM8Bpin!=pin)) error("Blready Set to pin %",PWM8Bpin);
|
|
PWM8Bpin=pin;
|
|
break;
|
|
case EXT_PWM9B: if(!(PinDef[pin].mode & PWM9B) || rp2350a) error("Invalid configuration");
|
|
if((PWM9Bpin!=99 && PWM9Bpin!=pin)) error("Blready Set to pin %",PWM9Bpin);
|
|
PWM9Bpin=pin;
|
|
break;
|
|
case EXT_PWM10B: if(!(PinDef[pin].mode & PWM10B) || rp2350a) error("Invalid configuration");
|
|
if((PWM10Bpin!=99 && PWM10Bpin!=pin)) error("Blready Set to pin %",PWM10Bpin);
|
|
PWM10Bpin=pin;
|
|
break;
|
|
case EXT_PWM11B: if(!(PinDef[pin].mode & PWM11B) || rp2350a) error("Invalid configuration");
|
|
if((PWM11Bpin!=99 && PWM11Bpin!=pin)) error("Blready Set to pin %",PWM11Bpin);
|
|
PWM11Bpin=pin;
|
|
break;
|
|
#endif
|
|
case EXT_FAST_TIMER: if(!(PinDef[pin].mode & PWM0B)) error("Invalid configuration");
|
|
if((PWM0Bpin!=99 && PWM0Bpin!=pin)) error("Already Set to pin %",PWM0Bpin);
|
|
PWM0Bpin=pin;
|
|
INT5Count = INT5Value = 0;
|
|
INT5Timer = INT5InitTimer = option; // only used for frequency and period measurement
|
|
tris = 1; ana = 1;
|
|
// PinSetBit(pin,TRISSET);
|
|
gpio_set_input_hysteresis_enabled(PinDef[pin].GPno,true);
|
|
gpio_set_function(PinDef[pin].GPno, GPIO_FUNC_PWM);
|
|
pwm_config cfg = pwm_get_default_config();
|
|
pwm_config_set_clkdiv_mode(&cfg, PWM_DIV_B_RISING);
|
|
pwm_config_set_clkdiv(&cfg, 1);
|
|
pwm_init(0, &cfg, false);
|
|
pwm_set_wrap(0, 49999);
|
|
pwm_clear_irq(0);
|
|
irq_set_exclusive_handler(PWM_IRQ_WRAP_1, on_pwm_wrap_1);
|
|
irq_set_enabled(PWM_IRQ_WRAP_1, true);
|
|
irq_set_priority(PWM_IRQ_WRAP_1,0);
|
|
pwm_set_irq1_enabled(0, true);
|
|
pwm_set_enabled(0, true);
|
|
break;
|
|
#endif
|
|
case EXT_I2C0SDA: if(!(PinDef[pin].mode & I2C0SDA)) error("Invalid configuration");
|
|
if(I2C0locked)error("I2C in use for SYSTEM I2C");
|
|
if((I2C0SDApin!=99 && I2C0SDApin!=pin)) error("Already Set to pin %",I2C0SDApin);
|
|
I2C0SDApin=pin;
|
|
break;
|
|
case EXT_I2C0SCL: if(!(PinDef[pin].mode & I2C0SCL)) error("Invalid configuration");
|
|
if(I2C0locked)error("I2C in use for SYSTEM I2C");
|
|
if((I2C0SCLpin!=99 && I2C0SCLpin!=pin)) error("Already Set to pin %",I2C0SCLpin);
|
|
I2C0SCLpin=pin;
|
|
break;
|
|
case EXT_I2C1SDA: if(!(PinDef[pin].mode & I2C1SDA)) error("Invalid configuration");
|
|
if(I2C1locked)error("I2C2 in use for SYSTEM I2C");
|
|
if((I2C1SDApin!=99) && I2C1SDApin!=pin) error("Already Set to pin %",I2C1SDApin);
|
|
I2C1SDApin=pin;
|
|
break;
|
|
case EXT_I2C1SCL: if(!(PinDef[pin].mode & I2C1SCL)) error("Invalid configuration");
|
|
if(I2C1locked)error("I2C2 in use for SYSTEM I2C");
|
|
if((I2C1SCLpin!=99 && I2C1SCLpin!=pin)) error("Already Set to pin %",I2C1SCLpin);
|
|
I2C1SCLpin=pin;
|
|
break;
|
|
default: error("Invalid configuration");
|
|
return;
|
|
}
|
|
ExtCurrentConfig[pin] = cfg;
|
|
if(cfg<=EXT_INT_BOTH || cfg==EXT_ADCRAW){
|
|
// *GetPortAddr(pin, ana ? ANSELCLR : ANSELSET) = (1 << GetPinBit(pin));// if ana = 1 then it is a digital I/O
|
|
PinSetBit(pin, tris ? TRISSET : TRISCLR); // if tris = 1 then it is an input
|
|
if(!tris && (pinmask & (1<<PinDef[pin].GPno))){
|
|
gpio_put(PinDef[pin].GPno,GPIO_PIN_SET);
|
|
}
|
|
pinmask &= (~(1<<PinDef[pin].GPno));
|
|
if(cfg == EXT_NOT_CONFIG) ExtSet(pin, 0); // set the default output to low
|
|
if(ana==0)PinSetBit(pin, ANSELSET);
|
|
}
|
|
else if(cfg>=EXT_UART0TX && cfg<=EXT_UART1RX){
|
|
gpio_set_function(PinDef[pin].GPno, GPIO_FUNC_UART);
|
|
if(cfg==EXT_UART0RX || cfg==EXT_UART1RX)gpio_set_pulls(PinDef[pin].GPno,true,false);
|
|
}
|
|
else if(cfg>=EXT_I2C0SDA && cfg<=EXT_I2C1SCL)gpio_set_function(PinDef[pin].GPno, GPIO_FUNC_I2C);
|
|
else if(cfg>=EXT_SPI0RX && cfg<=EXT_SPI1SCK)gpio_set_function(PinDef[pin].GPno, GPIO_FUNC_SPI);
|
|
#ifdef rp2350
|
|
else if(cfg>=EXT_PWM0A && cfg<=(rp2350a ? EXT_PWM7B : EXT_PWM11B))gpio_set_function(PinDef[pin].GPno, GPIO_FUNC_PWM);
|
|
#else
|
|
else if(cfg>=EXT_PWM0A && cfg<=EXT_PWM7B)gpio_set_function(PinDef[pin].GPno, GPIO_FUNC_PWM);
|
|
#endif
|
|
else if(cfg==EXT_PIO0_OUT){
|
|
gpio_set_input_enabled(PinDef[pin].GPno, true);
|
|
gpio_set_function(PinDef[pin].GPno, GPIO_FUNC_PIO0);
|
|
}
|
|
else if(cfg==EXT_PIO1_OUT){
|
|
gpio_set_input_enabled(PinDef[pin].GPno, true);
|
|
gpio_set_function(PinDef[pin].GPno, GPIO_FUNC_PIO1);
|
|
}
|
|
#ifdef rp2350
|
|
else if(cfg==EXT_PIO2_OUT){
|
|
gpio_set_input_enabled(PinDef[pin].GPno, true);
|
|
gpio_set_function(PinDef[pin].GPno, GPIO_FUNC_PIO2);
|
|
}
|
|
#endif
|
|
uSec(2);
|
|
}
|
|
extern int adc_clk_div;
|
|
#ifndef rp2350
|
|
#ifdef PICOMITEVGA
|
|
int64_t ExtInp(int pin){
|
|
#else
|
|
int64_t __not_in_flash_func(ExtInp)(int pin){
|
|
#endif
|
|
#else
|
|
int64_t __not_in_flash_func(ExtInp)(int pin){
|
|
#endif
|
|
if(ExtCurrentConfig[pin]==EXT_ANA_IN || ExtCurrentConfig[pin]==EXT_ADCRAW){
|
|
if(adc_clk_div!=adc_hw->div){
|
|
SetADCFreq(500000.0);
|
|
}
|
|
|
|
if(last_adc!=pin){
|
|
last_adc=pin;
|
|
adc_select_input(PinDef[pin].ADCpin);
|
|
}
|
|
int a= adc_read();
|
|
if(adc_hw->cs & (ADC_CS_ERR_STICKY_BITS | ADC_CS_ERR_BITS)) {
|
|
hw_set_bits(&adc_hw->cs, ADC_CS_ERR_STICKY_BITS);
|
|
a=-1;
|
|
}
|
|
return a;
|
|
} else if(ExtCurrentConfig[pin] == EXT_FREQ_IN || ExtCurrentConfig[pin] == EXT_PER_IN) {
|
|
// select input channel
|
|
if(pin == Option.INT1pin) return INT1Value;
|
|
if(pin == Option.INT2pin) return INT2Value;
|
|
if(pin == Option.INT3pin) return INT3Value;
|
|
if(pin == Option.INT4pin) return INT4Value;
|
|
} else if(ExtCurrentConfig[pin] == EXT_CNT_IN) {
|
|
// select input channel
|
|
if(pin == Option.INT1pin) return INT1Count;
|
|
if(pin == Option.INT2pin) return INT2Count;
|
|
if(pin == Option.INT3pin) return INT3Count;
|
|
if(pin == Option.INT4pin) return INT4Count;
|
|
} else if(ExtCurrentConfig[pin] == EXT_DIG_OUT) {
|
|
return gpio_get_out_level(PinDef[pin].GPno);
|
|
} else {
|
|
return gpio_get(PinDef[pin].GPno);
|
|
}
|
|
return 0;
|
|
}
|
|
/* @endcond */
|
|
void MIPS16 cmd_setpin(void) {
|
|
int i, pin, pin2=0, pin3=0, value=-1, value2=0, value3=0, option = 0;
|
|
getargs(&cmdline, 7, (unsigned char *)",");
|
|
if(argc%2 == 0 || argc < 3) error("Argument count");
|
|
char code;
|
|
if(!(code=codecheck(argv[0])))argv[0]+=2;
|
|
pin = getinteger(argv[0]);
|
|
if(!code)pin=codemap(pin);
|
|
|
|
if(checkstring(argv[2], (unsigned char *)"OFF") || checkstring(argv[2], (unsigned char *)"0"))
|
|
value = EXT_NOT_CONFIG;
|
|
else if(checkstring(argv[2], (unsigned char *)"AIN"))
|
|
value = EXT_ANA_IN;
|
|
else if(checkstring(argv[2], (unsigned char *)"ARAW"))
|
|
value = EXT_ADCRAW;
|
|
else if(checkstring(argv[2], (unsigned char *)"DIN"))
|
|
value = EXT_DIG_IN;
|
|
else if(checkstring(argv[2], (unsigned char *)"FIN"))
|
|
value = EXT_FREQ_IN;
|
|
else if(checkstring(argv[2], (unsigned char *)"PIN"))
|
|
value = EXT_PER_IN;
|
|
else if(checkstring(argv[2], (unsigned char *)"CIN"))
|
|
value = EXT_CNT_IN;
|
|
else if(checkstring(argv[2], (unsigned char *)"INTH"))
|
|
value = EXT_INT_HI;
|
|
else if(checkstring(argv[2], (unsigned char *)"INTL"))
|
|
value = EXT_INT_LO;
|
|
else if(checkstring(argv[2], (unsigned char *)"DOUT"))
|
|
value = EXT_DIG_OUT;
|
|
else if(checkstring(argv[2], (unsigned char *)"HEARTBEAT"))
|
|
value = EXT_HEARTBEAT;
|
|
else if(checkstring(argv[2], (unsigned char *)"INTB"))
|
|
value = EXT_INT_BOTH;
|
|
else if(checkstring(argv[2], (unsigned char *)"IR"))
|
|
value = EXT_IR;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM0A"))
|
|
value = EXT_PWM0A;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM1A"))
|
|
value = EXT_PWM1A;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM2A"))
|
|
value = EXT_PWM2A;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM3A"))
|
|
value = EXT_PWM3A;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM4A"))
|
|
value = EXT_PWM4A;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM5A"))
|
|
value = EXT_PWM5A;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM6A"))
|
|
value = EXT_PWM6A;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM7A"))
|
|
value = EXT_PWM7A;
|
|
#ifdef rp2350
|
|
else if(checkstring(argv[2], (unsigned char *)"FFIN"))
|
|
value = EXT_FAST_TIMER;
|
|
#endif
|
|
#ifdef rp2350
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM8A"))
|
|
value = EXT_PWM8A;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM9A"))
|
|
value = EXT_PWM9A;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM10A"))
|
|
value = EXT_PWM10A;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM711"))
|
|
value = EXT_PWM11A;
|
|
#endif
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM0B"))
|
|
value = EXT_PWM0B;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM1B"))
|
|
value = EXT_PWM1B;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM2B"))
|
|
value = EXT_PWM2B;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM3B"))
|
|
value = EXT_PWM3B;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM4B"))
|
|
value = EXT_PWM4B;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM5B"))
|
|
value = EXT_PWM5B;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM6B"))
|
|
value = EXT_PWM6B;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM7B"))
|
|
value = EXT_PWM7B;
|
|
#ifdef rp2350
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM8B"))
|
|
value = EXT_PWM8B;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM9B"))
|
|
value = EXT_PWM9B;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM10B"))
|
|
value = EXT_PWM10B;
|
|
else if(checkstring(argv[2], (unsigned char *)"PWM11B"))
|
|
value = EXT_PWM11B;
|
|
#endif
|
|
else if(checkstring(argv[2], (unsigned char *)"PIO0"))
|
|
value = EXT_PIO0_OUT;
|
|
else if(checkstring(argv[2], (unsigned char *)"PIO1"))
|
|
value = EXT_PIO1_OUT;
|
|
#ifdef rp2350
|
|
else if(checkstring(argv[2], (unsigned char *)"PIO2"))
|
|
value = EXT_PIO2_OUT;
|
|
#endif
|
|
else if(checkstring(argv[2],(unsigned char *)"PWM")){
|
|
if(PinDef[pin].mode & PWM0A)value = EXT_PWM0A;
|
|
else if(PinDef[pin].mode & PWM0B)value = EXT_PWM0B;
|
|
else if(PinDef[pin].mode & PWM1A)value = EXT_PWM1A;
|
|
else if(PinDef[pin].mode & PWM1B)value = EXT_PWM1B;
|
|
else if(PinDef[pin].mode & PWM2A)value = EXT_PWM2A;
|
|
else if(PinDef[pin].mode & PWM2B)value = EXT_PWM2B;
|
|
else if(PinDef[pin].mode & PWM3A)value = EXT_PWM3A;
|
|
else if(PinDef[pin].mode & PWM3B)value = EXT_PWM3B;
|
|
else if(PinDef[pin].mode & PWM4A)value = EXT_PWM4A;
|
|
else if(PinDef[pin].mode & PWM4B)value = EXT_PWM4B;
|
|
else if(PinDef[pin].mode & PWM5A)value = EXT_PWM5A;
|
|
else if(PinDef[pin].mode & PWM5B)value = EXT_PWM5B;
|
|
else if(PinDef[pin].mode & PWM6A)value = EXT_PWM6A;
|
|
else if(PinDef[pin].mode & PWM6B)value = EXT_PWM6B;
|
|
else if(PinDef[pin].mode & PWM7A)value = EXT_PWM7A;
|
|
else if(PinDef[pin].mode & PWM7B)value = EXT_PWM7B;
|
|
#ifdef rp2350
|
|
else if(PinDef[pin].mode & PWM8A)value = EXT_PWM8A;
|
|
else if(PinDef[pin].mode & PWM8B)value = EXT_PWM8B;
|
|
else if(PinDef[pin].mode & PWM9A)value = EXT_PWM9A;
|
|
else if(PinDef[pin].mode & PWM9B)value = EXT_PWM9B;
|
|
else if(PinDef[pin].mode & PWM10A)value = EXT_PWM10A;
|
|
else if(PinDef[pin].mode & PWM10B)value = EXT_PWM10B;
|
|
else if(PinDef[pin].mode & PWM11A)value = EXT_PWM11A;
|
|
else if(PinDef[pin].mode & PWM11B)value = EXT_PWM11B;
|
|
#endif
|
|
else error("Invalid configuration");
|
|
} else if(checkstring(argv[2],(unsigned char *)"INT")){
|
|
if(pin==Option.INT1pin)value = EXT_INT1;
|
|
else if(pin==Option.INT2pin)value = EXT_INT2;
|
|
else if(pin==Option.INT3pin)value = EXT_INT3;
|
|
else if(pin==Option.INT4pin)value = EXT_INT4;
|
|
else error("Invalid configuration");
|
|
}
|
|
if(value!=-1)goto process;
|
|
if(argc<5)error("Syntax");
|
|
if(checkstring(argv[4],(unsigned char *)"COM1")){
|
|
if(!(code=codecheck(argv[2])))argv[2]+=2;
|
|
pin2 = getinteger(argv[2]);
|
|
if(!code)pin2=codemap(pin2);
|
|
if(PinDef[pin].mode & UART0TX)value = EXT_UART0TX;
|
|
else if(PinDef[pin].mode & UART0RX)value = EXT_UART0RX;
|
|
else error("Invalid configuration");
|
|
if(PinDef[pin2].mode & UART0TX)value2 = EXT_UART0TX;
|
|
else if(PinDef[pin2].mode & UART0RX)value2 = EXT_UART0RX;
|
|
else error("Invalid configuration");
|
|
if(value==value2)error("Invalid configuration");
|
|
} else if(checkstring(argv[4],(unsigned char *)"COM2")){
|
|
if(!(code=codecheck(argv[2])))argv[2]+=2;
|
|
pin2 = getinteger(argv[2]);
|
|
if(!code)pin2=codemap(pin2);
|
|
if(PinDef[pin].mode & UART1TX)value = EXT_UART1TX;
|
|
else if(PinDef[pin].mode & UART1RX)value = EXT_UART1RX;
|
|
else error("Invalid configuration");
|
|
if(PinDef[pin2].mode & UART1TX)value2 = EXT_UART1TX;
|
|
else if(PinDef[pin2].mode & UART1RX)value2 = EXT_UART1RX;
|
|
else error("Invalid configuration");
|
|
if(value==value2)error("Invalid configuration");
|
|
} else if(checkstring(argv[4],(unsigned char *)"I2C")){
|
|
if(!(code=codecheck(argv[2])))argv[2]+=2;
|
|
pin2 = getinteger(argv[2]);
|
|
if(!code)pin2=codemap(pin2);
|
|
if(PinDef[pin].mode & I2C0SCL)value = EXT_I2C0SCL;
|
|
else if(PinDef[pin].mode & I2C0SDA)value = EXT_I2C0SDA;
|
|
else error("Invalid configuration");
|
|
if(PinDef[pin2].mode & I2C0SCL)value2 = EXT_I2C0SCL;
|
|
else if(PinDef[pin2].mode & I2C0SDA)value2 = EXT_I2C0SDA;
|
|
else error("Invalid configuration");
|
|
if(value==value2)error("Invalid configuration");
|
|
} else if(checkstring(argv[4],(unsigned char *)"I2C2")){
|
|
if(!(code=codecheck(argv[2])))argv[2]+=2;
|
|
pin2 = getinteger(argv[2]);
|
|
if(!code)pin2=codemap(pin2);
|
|
if(PinDef[pin].mode & I2C1SCL)value = EXT_I2C1SCL;
|
|
else if(PinDef[pin].mode & I2C1SDA)value = EXT_I2C1SDA;
|
|
else error("Invalid configuration");
|
|
if(PinDef[pin2].mode & I2C1SCL)value2 = EXT_I2C1SCL;
|
|
else if(PinDef[pin2].mode & I2C1SDA)value2 = EXT_I2C1SDA;
|
|
else error("Invalid configuration");
|
|
if(value==value2)error("Invalid configuration");
|
|
}
|
|
if(value!=-1)goto process;
|
|
if(argc<7)error("Syntax");
|
|
if(checkstring(argv[6],(unsigned char *)"SPI")){
|
|
if(!(code=codecheck(argv[2])))argv[2]+=2;
|
|
pin2 = getinteger(argv[2]);
|
|
if(!code)pin2=codemap(pin2);
|
|
if(!(code=codecheck(argv[4])))argv[4]+=2;
|
|
pin3 = getinteger(argv[4]);
|
|
if(!code)pin3=codemap(pin3);
|
|
if(PinDef[pin].mode & SPI0RX)value = EXT_SPI0RX;
|
|
else if(PinDef[pin].mode & SPI0TX)value = EXT_SPI0TX;
|
|
else if(PinDef[pin].mode & SPI0SCK)value = EXT_SPI0SCK;
|
|
else error("Invalid configuration");
|
|
if(PinDef[pin2].mode & SPI0RX)value2 = EXT_SPI0RX;
|
|
else if(PinDef[pin2].mode & SPI0TX)value2 = EXT_SPI0TX;
|
|
else if(PinDef[pin2].mode & SPI0SCK)value2 = EXT_SPI0SCK;
|
|
else error("Invalid configuration");
|
|
if(PinDef[pin3].mode & SPI0RX)value3 = EXT_SPI0RX;
|
|
else if(PinDef[pin3].mode & SPI0TX)value3 = EXT_SPI0TX;
|
|
else if(PinDef[pin3].mode & SPI0SCK)value3 = EXT_SPI0SCK;
|
|
else error("Invalid configuration");
|
|
if(value==value2 || value==value3 || value2==value3)error("Invalid configuration");
|
|
} else if(checkstring(argv[6],(unsigned char *)"SPI2")){
|
|
if(!(code=codecheck(argv[2])))argv[2]+=2;
|
|
pin2 = getinteger(argv[2]);
|
|
if(!code)pin2=codemap(pin2);
|
|
if(!(code=codecheck(argv[4])))argv[4]+=2;
|
|
pin3 = getinteger(argv[4]);
|
|
if(!code)pin3=codemap(pin3);
|
|
if(PinDef[pin].mode & SPI1RX)value = EXT_SPI1RX;
|
|
else if(PinDef[pin].mode & SPI1TX)value = EXT_SPI1TX;
|
|
else if(PinDef[pin].mode & SPI1SCK)value = EXT_SPI1SCK;
|
|
else error("Invalid configuration");
|
|
if(PinDef[pin2].mode & SPI1RX)value2 = EXT_SPI1RX;
|
|
else if(PinDef[pin2].mode & SPI1TX)value2 = EXT_SPI1TX;
|
|
else if(PinDef[pin2].mode & SPI1SCK)value2 = EXT_SPI1SCK;
|
|
else error("Invalid configuration");
|
|
if(PinDef[pin3].mode & SPI1RX)value3 = EXT_SPI1RX;
|
|
else if(PinDef[pin3].mode & SPI1TX)value3 = EXT_SPI1TX;
|
|
else if(PinDef[pin3].mode & SPI1SCK)value3 = EXT_SPI1SCK;
|
|
else error("Invalid configuration");
|
|
if(value==value2 || value==value3 || value2==value3)error("Invalid configuration");
|
|
} else error("Syntax");
|
|
// value = getint(argv[2], 1, 9);
|
|
process:
|
|
// check for any options
|
|
switch(value) {
|
|
case EXT_ANA_IN:
|
|
case EXT_ADCRAW: if(argc == 5) {
|
|
option = getint((argv[4]), 8, 12);
|
|
if(option & 1)error("Invalid bit count");
|
|
} else
|
|
option = 12;
|
|
break;
|
|
|
|
case EXT_DIG_IN: if(argc == 5) {
|
|
if(checkstring(argv[4], (unsigned char *)"PULLUP")) option = CNPUSET;
|
|
else if(checkstring(argv[4], (unsigned char *)"PULLDOWN")) {
|
|
#ifdef rp2350
|
|
PinSetBit(pin,TRISCLR);
|
|
PinSetBit(pin,LATCLR);
|
|
PinSetBit(pin,TRISSET);
|
|
#endif
|
|
option = CNPDSET;
|
|
}
|
|
else error("Invalid configuration");
|
|
} else
|
|
option = 0;
|
|
break;
|
|
case EXT_INT_HI:
|
|
case EXT_INT_LO:
|
|
case EXT_INT_BOTH: if(argc == 7) {
|
|
if(checkstring(argv[6], (unsigned char *)"PULLUP")) option = CNPUSET;
|
|
else if(checkstring(argv[6], (unsigned char *)"PULLDOWN")) {
|
|
#ifdef rp2350
|
|
PinSetBit(pin,TRISCLR);
|
|
PinSetBit(pin,LATCLR);
|
|
PinSetBit(pin,TRISSET);
|
|
#endif
|
|
option = CNPDSET;
|
|
}
|
|
else error("Invalid configuration");
|
|
} else
|
|
option = 0;
|
|
break;
|
|
case EXT_FREQ_IN: if(argc == 5)
|
|
option = getint((argv[4]), 1, 100000);
|
|
else
|
|
option = 1000;
|
|
break;
|
|
case EXT_PER_IN: if(argc == 5)
|
|
option = getint((argv[4]), 1, 10000);
|
|
else
|
|
option = 1;
|
|
break;
|
|
case EXT_CNT_IN: if(argc == 5)
|
|
option = getint((argv[4]), 1, 10);
|
|
else
|
|
option = 1;
|
|
break;
|
|
#ifdef rp2350
|
|
case EXT_FAST_TIMER: if(pin!=FAST_TIMER_PIN)error("Use pin2/GP1 for fast counter");
|
|
if(BacklightSlice==0)error("Channel in use for backlight");
|
|
if(Option.AUDIO_SLICE==0)error("Channel in use for Audio");
|
|
if(CameraSlice==0)error("Channel in use for Camera");
|
|
if(argc == 5)
|
|
option = getint((argv[4]), 1, 100000);
|
|
else
|
|
option = 1000;
|
|
break;
|
|
#endif
|
|
case EXT_DIG_OUT:
|
|
case EXT_HEARTBEAT:
|
|
option=0;
|
|
default: if(argc > 3 && !value2) error("Unexpected text");
|
|
}
|
|
// this allows the user to set a software interrupt on the touch IRQ pin if the GUI environment is not enabled
|
|
if(pin == Option.TOUCH_IRQ)
|
|
#ifdef GUICONTROLS
|
|
if(Option.MaxCtrls==0)
|
|
#endif
|
|
{
|
|
if(value == EXT_INT_HI || value == EXT_INT_LO || value == EXT_INT_BOTH)
|
|
ExtCurrentConfig[pin] = value;
|
|
else if(value == EXT_NOT_CONFIG) {
|
|
ExtCurrentConfig[pin] = EXT_BOOT_RESERVED;
|
|
for(i = 0; i < NBRINTERRUPTS; i++)
|
|
if(inttbl[i].pin == pin)
|
|
inttbl[i].pin = 0; // disable the software interrupt on this pin
|
|
}
|
|
else
|
|
error("Pin %/| is reserved on startup", pin,pin);
|
|
}
|
|
|
|
CheckPin(pin, CP_IGNORE_INUSE);
|
|
ExtCfg(pin, value, option);
|
|
|
|
if(value2) {
|
|
CheckPin(pin2, CP_IGNORE_INUSE);
|
|
ExtCfg(pin2, value2, option);
|
|
}
|
|
if(value3) {
|
|
CheckPin(pin3, CP_IGNORE_INUSE);
|
|
ExtCfg(pin3, value3, option);
|
|
}
|
|
|
|
|
|
if(value == EXT_INT_HI || value == EXT_INT_LO || value == EXT_INT_BOTH) {
|
|
// we need to set up a software interrupt
|
|
if(argc < 5) error("Argument count");
|
|
for(i = 0; i < NBRINTERRUPTS; i++) if(inttbl[i].pin == 0) break;
|
|
if(i >= NBRINTERRUPTS) error("Too many interrupts");
|
|
inttbl[i].pin = pin;
|
|
inttbl[i].intp = (char *)GetIntAddress(argv[4]); // get the interrupt routine's location
|
|
inttbl[i].last = ExtInp(pin); // save the current pin value for the first test
|
|
switch(value) { // and set trigger polarity
|
|
case EXT_INT_HI: inttbl[i].lohi = T_LOHI; break;
|
|
case EXT_INT_LO: inttbl[i].lohi = T_HILO; break;
|
|
case EXT_INT_BOTH: inttbl[i].lohi = T_BOTH; break;
|
|
}
|
|
InterruptUsed = true;
|
|
}
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
bool __no_inline_not_in_flash_func(bb_get_bootsel_button)() {
|
|
const uint CS_PIN_INDEX = 1;
|
|
disable_interrupts_pico();
|
|
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
|
GPIO_OVERRIDE_LOW << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
|
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
|
for (volatile int i = 0; i < 100; ++i);
|
|
bool button_state = !(sio_hw->gpio_hi_in & (1u << CS_PIN_INDEX));
|
|
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
|
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
|
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
|
enable_interrupts_pico();
|
|
|
|
return button_state;
|
|
}
|
|
/* @endcond */
|
|
|
|
void fun_pin(void) {
|
|
char code;
|
|
int pin, i, j, b[ANA_AVERAGE];
|
|
MMFLOAT t;
|
|
if(checkstring(ep, (unsigned char *)"TEMP")){
|
|
if(ADCDualBuffering || dmarunning)error("ADC in use");
|
|
adc_init();
|
|
adc_set_temp_sensor_enabled(true);
|
|
#ifdef rp2350
|
|
adc_select_input((rp2350a ? 4 : 8));
|
|
#else
|
|
adc_select_input(4);
|
|
#endif
|
|
last_adc=4;
|
|
t=(MMFLOAT)adc_read()/4095.0*VCC;
|
|
fret=(27.0-(t-0.706)/0.001721);
|
|
targ=T_NBR;
|
|
return;
|
|
}
|
|
if(checkstring(ep, (unsigned char *)"BOOTSEL")){
|
|
iret=bb_get_bootsel_button();
|
|
targ=T_INT;
|
|
return;
|
|
}
|
|
|
|
if(!(code=codecheck(ep)))ep+=2;
|
|
pin = getinteger(ep);
|
|
if(!code)pin=codemap(pin);
|
|
if(IsInvalidPin(pin)) error("Invalid pin");
|
|
switch(ExtCurrentConfig[pin]) {
|
|
case EXT_DIG_IN:
|
|
case EXT_CNT_IN:
|
|
case EXT_INT_HI:
|
|
case EXT_INT_LO:
|
|
case EXT_INT_BOTH:
|
|
case EXT_DIG_OUT:
|
|
case EXT_PIO0_OUT:
|
|
case EXT_PIO1_OUT:
|
|
#ifdef rp2350
|
|
case EXT_PIO2_OUT:
|
|
#endif
|
|
iret = ExtInp(pin);
|
|
targ = T_INT;
|
|
return;
|
|
#ifdef rp2350
|
|
case EXT_FAST_TIMER:
|
|
fret = (MMFLOAT)INT5Value * (MMFLOAT)1000.0 / (MMFLOAT)INT5InitTimer;
|
|
targ = T_NBR;
|
|
return;
|
|
#endif
|
|
case EXT_PER_IN: // if period measurement get the count and average it over the number of cycles
|
|
if(pin == Option.INT1pin) fret = (MMFLOAT)ExtInp(pin) / (MMFLOAT)INT1InitTimer;
|
|
else if(pin == Option.INT2pin) fret = (MMFLOAT)ExtInp(pin) / (MMFLOAT)INT2InitTimer;
|
|
else if(pin == Option.INT3pin) fret = (MMFLOAT)ExtInp(pin) / (MMFLOAT)INT3InitTimer;
|
|
else if(pin == Option.INT4pin) fret = (MMFLOAT)ExtInp(pin) / (MMFLOAT)INT4InitTimer;
|
|
targ = T_NBR;
|
|
return;
|
|
case EXT_FREQ_IN: // if frequency measurement get the count and scale the reading
|
|
if(pin == Option.INT1pin) fret = (MMFLOAT)(ExtInp(pin)) * (MMFLOAT)1000.0 / (MMFLOAT)INT1InitTimer;
|
|
else if(pin == Option.INT2pin) fret = (MMFLOAT)(ExtInp(pin)) * (MMFLOAT)1000.0 / (MMFLOAT)INT2InitTimer;
|
|
else if(pin == Option.INT3pin) fret = (MMFLOAT)(ExtInp(pin)) * (MMFLOAT)1000.0 / (MMFLOAT)INT3InitTimer;
|
|
else if(pin == Option.INT4pin) fret = (MMFLOAT)(ExtInp(pin)) * (MMFLOAT)1000.0 / (MMFLOAT)INT4InitTimer;
|
|
targ = T_NBR;
|
|
return;
|
|
case EXT_ADCRAW:
|
|
if(ADCDualBuffering || dmarunning)error("ADC in use");
|
|
iret=ExtInp(pin);
|
|
targ=T_INT;
|
|
return;
|
|
case EXT_ANA_IN:
|
|
if(ADCDualBuffering || dmarunning)error("ADC in use");
|
|
for(i = 0; i < ANA_AVERAGE; i++) {
|
|
b[i] = ExtInp(pin); // get the value
|
|
for(j = i; j > 0; j--) { // and sort into position
|
|
if(b[j - 1] < b[j]) {
|
|
t = b[j - 1];
|
|
b[j - 1] = b[j];
|
|
b[j] = t;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
// we then discard the top ANA_DISCARD samples and the bottom ANA_DISCARD samples and add up the remainder
|
|
for(j = 0, i = ANA_DISCARD; i < ANA_AVERAGE - ANA_DISCARD; i++) j += b[i];
|
|
|
|
// the total is averaged and scaled
|
|
fret = FMul((MMFLOAT)j , VCC) / (MMFLOAT)(4095 * (ANA_AVERAGE - ANA_DISCARD*2));
|
|
targ = T_NBR;
|
|
return;
|
|
|
|
default: error("Pin %/| is not an input",pin,pin);
|
|
}
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
int CheckPin(int pin, int action) {
|
|
|
|
#ifdef rp2350
|
|
if(rp2350a && pin>44)error("Pin | is invalid", pin);
|
|
#endif
|
|
|
|
if(pin < 1 || pin > NBRPINS || (PinDef[pin].mode & UNUSED)) {
|
|
if(!(action & CP_NOABORT)) error("Pin %/| is invalid", pin,pin);
|
|
return false;
|
|
}
|
|
|
|
if(!(action & CP_IGNORE_INUSE) && ExtCurrentConfig[pin] >= EXT_DS18B20_RESERVED && ExtCurrentConfig[pin] < EXT_COM_RESERVED) {
|
|
if(!(action & CP_NOABORT)) error("Pin %/| is in use", pin,pin);
|
|
return false;
|
|
}
|
|
|
|
if(!(action & CP_IGNORE_BOOTRES) && ExtCurrentConfig[pin] >= EXT_BOOT_RESERVED) {
|
|
if(!(action & CP_NOABORT)) {
|
|
error("Pin %/| is reserved on startup", pin,pin);
|
|
uSec(1000000);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if(!(action & CP_IGNORE_RESERVED) && ExtCurrentConfig[pin] >= EXT_DS18B20_RESERVED) {
|
|
if(!(action & CP_NOABORT)) error("Pin %/| is in use", pin,pin);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
/* @endcond */
|
|
// this is invoked as a command (ie, port(3, 8) = Value)
|
|
// first get the arguments then step over the closing bracket. Search through the rest of the command line looking
|
|
// for the equals sign and step over it, evaluate the rest of the command and set the pins accordingly
|
|
void cmd_port(void) {
|
|
int pin, nbr, value, code, pincode;
|
|
int i;
|
|
getargs(&cmdline, NBRPINS * 4, (unsigned char *)",");
|
|
|
|
if((argc & 0b11) != 0b11) error("Invalid syntax");
|
|
if(!strchr((char *)cmdline,')'))error ("Syntax");
|
|
// step over the equals sign and get the value for the assignment
|
|
while(*cmdline && tokenfunction(*cmdline) != op_equal) cmdline++;
|
|
if(!*cmdline) error("Invalid syntax");
|
|
++cmdline;
|
|
if(!*cmdline) error("Invalid syntax");
|
|
value = getinteger(cmdline);
|
|
uint64_t mask=0,setmask=0, readmask;
|
|
|
|
for(i = 0; i < argc; i += 4) {
|
|
code=0;
|
|
if(!(code=codecheck(argv[i])))argv[i]+=2;
|
|
pincode = getinteger(argv[i]);
|
|
nbr = getinteger(argv[i + 2]);
|
|
if(nbr < 0 || (pincode == 0 && code!=0) || (pincode<0)) error("Invalid argument");
|
|
|
|
while(nbr) {
|
|
if(!code)pin=codemap(pincode);
|
|
else pin=pincode;
|
|
if(IsInvalidPin(pin) || !(ExtCurrentConfig[pin] == EXT_DIG_OUT )) error("Invalid output pin");
|
|
gpio_set_input_enabled(PinDef[pin].GPno, true);
|
|
mask |=(1<<PinDef[pin].GPno);
|
|
if(value & 1)setmask |= (1<<PinDef[pin].GPno);
|
|
value >>= 1;
|
|
nbr--;
|
|
pincode++;
|
|
}
|
|
}
|
|
readmask=gpio_get_all64();
|
|
readmask &=mask;
|
|
gpio_xor_mask64(setmask ^ readmask);
|
|
#ifdef rp2350
|
|
#ifdef PICOMITEWEB
|
|
int n=NBRPINS;
|
|
#else
|
|
int n=rp2350a ? 44: NBRPINS;
|
|
#endif
|
|
#else
|
|
int n=NBRPINS;
|
|
#endif
|
|
|
|
for(int i=0;i<n;i++){
|
|
if(mask & 1)gpio_set_input_enabled(PinDef[i].GPno, false);
|
|
mask>>=1;
|
|
}
|
|
}
|
|
|
|
|
|
void fun_distance(void) {
|
|
int trig, echo,techo;
|
|
|
|
getargs(&ep, 3, (unsigned char *)",");
|
|
if((argc &1) != 1) error("Invalid syntax");
|
|
char code;
|
|
if(!(code=codecheck(argv[0])))argv[0]+=2;
|
|
trig = getinteger(argv[0]);
|
|
if(!code)trig=codemap(trig);
|
|
if(argc == 3){
|
|
if(!(code=codecheck(argv[2])))argv[2]+=2;
|
|
echo = getinteger(argv[2]);
|
|
if(!code)echo=codemap(echo);
|
|
}
|
|
else
|
|
echo = trig; // they are the same if it is a 3-pin device
|
|
if(IsInvalidPin(trig) || IsInvalidPin(echo)) error("Invalid pin |",echo);
|
|
if(ExtCurrentConfig[trig] >= EXT_COM_RESERVED || ExtCurrentConfig[echo] >= EXT_COM_RESERVED) error("Pin %/| is in use",trig,trig);
|
|
ExtCfg(echo, EXT_DIG_IN, CNPUSET); // setup the echo input
|
|
PinSetBit(trig, LATCLR); // trigger output must start low
|
|
ExtCfg(trig, EXT_DIG_OUT, 0); // setup the trigger output
|
|
PinSetBit(trig, LATSET); uSec(20); PinSetBit(trig, LATCLR); // pulse the trigger
|
|
uSec(50);
|
|
ExtCfg(echo, EXT_DIG_IN, CNPUSET); // this is in case the sensor is a 3-pin type
|
|
uSec(50);
|
|
PauseTimer = 0; // this is our timeout
|
|
while(PinRead(echo)) if(PauseTimer > 50) { fret = -2; return; } // wait for the acknowledgement pulse start
|
|
while(!PinRead(echo)) if(PauseTimer > 100) { fret = -2; return;}// then its end
|
|
PauseTimer = 0;
|
|
writeusclock(0);
|
|
while(PinRead(echo)) { // now wait for the echo pulse
|
|
if(PauseTimer > 38) { // timeout is 38mS
|
|
fret = -1;
|
|
return;
|
|
}
|
|
}
|
|
techo=readusclock();
|
|
// we have the echo, convert the time to centimeters
|
|
fret = FDiv((MMFLOAT)techo,58.0); //200 ticks per us, 58 us per cm
|
|
targ = T_NBR;
|
|
}
|
|
|
|
|
|
|
|
// this is invoked as a function (ie, x = port(10,8) )
|
|
void fun_port(void) {
|
|
int pin, nbr, i, value = 0, code, pincode;
|
|
|
|
getargs(&ep, NBRPINS * 4, (unsigned char *)",");
|
|
if((argc & 0b11) != 0b11) error("Invalid syntax");
|
|
uint64_t pinstate=gpio_get_all64();
|
|
for(i = argc - 3; i >= 0; i -= 4) {
|
|
code=0;
|
|
if(!(code=codecheck(argv[i])))argv[i]+=2;
|
|
pincode = getinteger(argv[i]);
|
|
nbr = getinteger(argv[i + 2]);
|
|
if(nbr < 0 || (pincode == 0 && code!=0) || (pincode<0)) error("Invalid argument");
|
|
pincode += nbr - 1; // we start by reading the most significant bit
|
|
|
|
while(nbr) {
|
|
if(!code)pin=codemap(pincode);
|
|
else pin=pincode;
|
|
if(IsInvalidPin(pin) || !(ExtCurrentConfig[pin] == EXT_DIG_IN || ExtCurrentConfig[pin] == EXT_DIG_OUT || ExtCurrentConfig[pin] == EXT_INT_HI || ExtCurrentConfig[pin] == EXT_INT_LO || ExtCurrentConfig[pin] == EXT_INT_BOTH)) error("Invalid input pin");
|
|
value <<= 1;
|
|
value |= (pinstate & (1<<PinDef[pin].GPno)? 1:0);
|
|
nbr--;
|
|
pincode--;
|
|
}
|
|
}
|
|
|
|
iret = value;
|
|
targ = T_INT;
|
|
}
|
|
|
|
|
|
void cmd_pulse(void) {
|
|
int pin, i, x, y;
|
|
MMFLOAT f;
|
|
|
|
getargs(&cmdline, 3, (unsigned char *)",");
|
|
if(argc != 3) error("Invalid syntax");
|
|
char code;
|
|
if(!(code=codecheck(argv[0])))argv[0]+=2;
|
|
pin = getinteger(argv[0]);
|
|
if(!code)pin=codemap(pin);
|
|
if(!(ExtCurrentConfig[pin] == EXT_DIG_OUT)) error("Pin %/| is not an output", pin,pin);
|
|
|
|
f = getnumber(argv[2]); // get the pulse width
|
|
if(f < 0) error("Number out of bounds");
|
|
x = f; // get the integer portion (in mSec)
|
|
y = (int)(FSub(f , (MMFLOAT)x) * 1000.0); // get the fractional portion (in uSec)
|
|
|
|
for(i = 0; i < NBR_PULSE_SLOTS; i++) // search looking to see if the pin is in use
|
|
if(PulseCnt[i] != 0 && PulsePin[i] == pin) {
|
|
mT4IntEnable(0); // disable the timer interrupt to prevent any conflicts while updating
|
|
PulseCnt[i] = x; // and if the pin is in use, set its time to the new setting or reset if the user wants to terminate
|
|
mT4IntEnable(1);
|
|
if(x == 0) PinSetBit(PulsePin[i], LATINV);
|
|
return;
|
|
}
|
|
|
|
if(x == 0 && y == 0) return; // silently ignore a zero pulse width
|
|
|
|
if(x < 3) { // if this is under 3 milliseconds just do it now
|
|
PinSetBit(pin, LATINV); // starting edge of the pulse
|
|
uSec(x * 1000 + y);
|
|
PinSetBit(pin, LATINV); // finishing edge
|
|
return;
|
|
}
|
|
|
|
for(i = 0; i < NBR_PULSE_SLOTS; i++)
|
|
if(PulseCnt[i] == 0) break; // find a spare slot
|
|
|
|
if(i >= NBR_PULSE_SLOTS) error("Too many concurrent PULSE commands");
|
|
|
|
PinSetBit(pin, LATINV); // starting edge of the pulse
|
|
if(x == 1) uSec(500); // prevent too narrow a pulse if there is just one count
|
|
PulsePin[i] = pin; // save the details
|
|
PulseCnt[i] = x;
|
|
PulseActive = true;
|
|
}
|
|
|
|
|
|
void fun_pulsin(void) { //allowas timeouts up to 10 seconds
|
|
int pin, polarity;
|
|
unsigned int t1, t2;
|
|
|
|
getargs(&ep, 7, (unsigned char *)",");
|
|
if((argc &1) != 1 || argc < 3) error("Invalid syntax");
|
|
char code;
|
|
if(!(code=codecheck(argv[0])))argv[0]+=2;
|
|
pin = getinteger(argv[0]);
|
|
if(!code)pin=codemap(pin);
|
|
if(IsInvalidPin(pin)) error("Invalid pin");
|
|
if(ExtCurrentConfig[pin] != EXT_DIG_IN) error("Pin %/| is not an input",pin,pin);
|
|
polarity = getinteger(argv[2]);
|
|
|
|
t1 = t2 = 100000; // default timeout is 100mS
|
|
if(argc >= 5) t1 = t2 = getint(argv[4], 5, 10000000);
|
|
if(argc == 7) t2 = getint(argv[6], 5, 10000000);
|
|
iret = -1; // in anticipation of a timeout
|
|
writeusclock(0);
|
|
if(polarity) {
|
|
while(PinRead(pin)) if(readusclock() > t1) return;
|
|
while(!PinRead(pin)) if(readusclock() > t1) return;
|
|
writeusclock(0);
|
|
while(PinRead(pin)) if(readusclock() > t2) return;
|
|
} else {
|
|
while(!PinRead(pin)) if(readusclock() > t1) return;
|
|
while(PinRead(pin)) if(readusclock() > t1) return;
|
|
writeusclock(0);
|
|
while(!PinRead(pin)) if(readusclock() > t2) return;
|
|
}
|
|
t1 = readusclock();
|
|
iret = t1;
|
|
targ = T_INT;
|
|
}
|
|
/****************************************************************************************************************************
|
|
IR routines
|
|
*****************************************************************************************************************************/
|
|
|
|
void cmd_ir(void) {
|
|
unsigned char *p;
|
|
int i, pin, dev, cmd;
|
|
if(checkstring(cmdline, (unsigned char *)"CLOSE")) {
|
|
if(IrState == IR_CLOSED) error("Not Open");
|
|
if(CallBackEnabled==1) gpio_set_irq_enabled_with_callback(PinDef[IRpin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
|
else gpio_set_irq_enabled(PinDef[IRpin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
|
IrInterrupt = NULL;
|
|
CallBackEnabled &= (~1);
|
|
ExtCfg(IRpin, EXT_NOT_CONFIG, 0);
|
|
} else if((p = checkstring(cmdline, (unsigned char *)"SEND"))) {
|
|
getargs(&p, 5, (unsigned char *)",");
|
|
char code;
|
|
if(!(code=codecheck(argv[0])))argv[0]+=2;
|
|
pin = getinteger(argv[0]);
|
|
if(!code)pin=codemap(pin);
|
|
if(IsInvalidPin(pin)) error("Invalid pin");
|
|
dev = getint(argv[2], 0, 0b11111);
|
|
cmd = getint(argv[4], 0, 0b1111111);
|
|
if(ExtCurrentConfig[pin] >= EXT_COM_RESERVED) error("Pin %/| is in use",pin,pin);
|
|
ExtCfg(pin, EXT_DIG_OUT, 0);
|
|
cmd = (dev << 7) | cmd;
|
|
IRSendSignal(pin, 186);
|
|
for(i = 0; i < 12; i++) {
|
|
uSec(600);
|
|
if(cmd & 1)
|
|
IRSendSignal(pin, 92);
|
|
else
|
|
IRSendSignal(pin, 46);
|
|
cmd >>= 1;
|
|
}
|
|
} else {
|
|
getargs(&cmdline, 5, (unsigned char *)",");
|
|
if(IRpin==99)error("Pin not configured for IR");
|
|
if(IrState != IR_CLOSED) error("Already open");
|
|
if(argc%2 == 0 || argc == 0) error("Invalid syntax");
|
|
IrVarType = 0;
|
|
IrDev = findvar(argv[0], V_FIND);
|
|
if(g_vartbl[g_VarIndex].type & T_CONST) error("Cannot change a constant");
|
|
if(g_vartbl[g_VarIndex].type & T_STR) error("Invalid variable");
|
|
if(g_vartbl[g_VarIndex].type & T_NBR) IrVarType |= 0b01;
|
|
IrCmd = findvar(argv[2], V_FIND);
|
|
if(g_vartbl[g_VarIndex].type & T_CONST) error("Cannot change a constant");
|
|
if(g_vartbl[g_VarIndex].type & T_STR) error("Invalid variable");
|
|
if(g_vartbl[g_VarIndex].type & T_NBR) IrVarType |= 0b10;
|
|
InterruptUsed = true;
|
|
IrInterrupt = GetIntAddress(argv[4]); // get the interrupt location
|
|
IrInit();
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
void IrInit(void) {
|
|
writeusclock(0);
|
|
if(ExtCurrentConfig[IRpin] >= EXT_COM_RESERVED) error("Pin %/% is in use",IRpin,IRpin);
|
|
ExtCfg(IRpin, EXT_IR, 0);
|
|
ExtCfg(IRpin, EXT_COM_RESERVED, 0);
|
|
if(!CallBackEnabled){
|
|
gpio_set_irq_enabled_with_callback(PinDef[IRpin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true, &gpio_callback);
|
|
CallBackEnabled=1;
|
|
} else {
|
|
gpio_set_irq_enabled(PinDef[IRpin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, true);
|
|
CallBackEnabled|=1;
|
|
}
|
|
IrReset();
|
|
}
|
|
|
|
|
|
void IrReset(void) {
|
|
IrState = IR_WAIT_START;
|
|
IrCount = 0;
|
|
writeIRclock(0);
|
|
}
|
|
|
|
|
|
// this modulates (at about 38KHz) the IR beam for transmit
|
|
// half_cycles is the number of half cycles to send. ie, 186 is about 2.4mSec
|
|
void IRSendSignal(int pin, int half_cycles) {
|
|
while(half_cycles--) {
|
|
PinSetBit(pin, LATINV);
|
|
uSec(13);
|
|
}
|
|
}
|
|
void MIPS16 set_PWM(int slice, MMFLOAT duty1, MMFLOAT duty2, int high1, int high2, int delaystart){
|
|
if(slice==0 && PWM0Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==0 && PWM0Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
#ifdef rp2350
|
|
if(slice==0 && fast_timer_active)error("Channel 0 in use for fast timer");
|
|
#endif
|
|
if(slice==1 && PWM1Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==1 && PWM1Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
if(slice==2 && PWM2Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==2 && PWM2Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
if(slice==3 && PWM3Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==3 && PWM3Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
if(slice==4 && PWM4Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==4 && PWM4Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
if(slice==5 && PWM5Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==5 && PWM5Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
if(slice==6 && PWM6Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==6 && PWM6Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
if(slice==7 && PWM7Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==7 && PWM7Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
#ifdef rp2350
|
|
if(slice==8 && PWM8Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==8 && PWM8Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
if(slice==9 && PWM9Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==9 && PWM9Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
if(slice==10 && PWM10Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==10 && PWM10Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
if(slice==11 && PWM11Apin==99 && duty1>=0.0)error("Pin not set for PWM");
|
|
if(slice==11 && PWM11Bpin==99 && duty2>=0.0)error("Pin not set for PWM");
|
|
#endif
|
|
if(slice==0 && PWM0Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM0Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==0 && PWM0Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM0Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
if(slice==1 && PWM1Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM1Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==1 && PWM1Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM1Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
if(slice==2 && PWM2Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM2Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==2 && PWM2Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM2Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
if(slice==3 && PWM3Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM3Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==3 && PWM3Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM3Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
if(slice==4 && PWM4Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM4Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==4 && PWM4Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM4Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
if(slice==5 && PWM5Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM5Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==5 && PWM5Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM5Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
if(slice==6 && PWM6Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM6Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==6 && PWM6Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM6Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
if(slice==7 && PWM7Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM7Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==7 && PWM7Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM7Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
#ifdef rp2350
|
|
if(slice==8 && PWM8Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM8Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==8 && PWM8Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM8Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
if(slice==9 && PWM9Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM9Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==9 && PWM9Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM9Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
if(slice==10 && PWM10Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM10Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==10 && PWM10Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM10Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
if(slice==11 && PWM11Apin!=99 && duty1>=0.0){
|
|
ExtCfg(PWM11Apin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_A, high1);
|
|
}
|
|
if(slice==11 && PWM11Bpin!=99 && duty2>=0.0){
|
|
ExtCfg(PWM11Bpin,EXT_COM_RESERVED,0);
|
|
pwm_set_chan_level(slice, PWM_CHAN_B, high2);
|
|
}
|
|
#endif
|
|
if(slice==0 && slice0==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice0=1;
|
|
}
|
|
if(slice==1 && slice1==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice1=1;
|
|
}
|
|
if(slice==2 && slice2==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice2=1;
|
|
}
|
|
if(slice==3 && slice3==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice3=1;
|
|
}
|
|
if(slice==4 && slice4==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice4=1;
|
|
}
|
|
if(slice==5 && slice5==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice5=1;
|
|
}
|
|
if(slice==6 && slice6==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice6=1;
|
|
}
|
|
if(slice==7 && slice7==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice7=1;
|
|
}
|
|
#ifdef rp2350
|
|
if(slice==8 && slice8==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice8=1;
|
|
}
|
|
if(slice==9 && slice9==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice9=1;
|
|
}
|
|
if(slice==10 && slice10==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice10=1;
|
|
}
|
|
if(slice==11 && slice11==0){
|
|
if(!delaystart)pwm_set_enabled(slice, true);
|
|
slice11=1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void PWMoff(int slice){
|
|
if(slice==0 && PWM0Apin!=99 && ExtCurrentConfig[PWM0Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM0Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==0 && PWM0Bpin!=99 && ExtCurrentConfig[PWM0Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM0Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==1 && PWM1Apin!=99 && ExtCurrentConfig[PWM1Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM1Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==1 && PWM1Bpin!=99 && ExtCurrentConfig[PWM1Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM1Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==2 && PWM2Apin!=99 && ExtCurrentConfig[PWM2Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM2Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==2 && PWM2Bpin!=99 && ExtCurrentConfig[PWM2Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM2Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==3 && PWM3Apin!=99 && ExtCurrentConfig[PWM3Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM3Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==3 && PWM3Bpin!=99 && ExtCurrentConfig[PWM3Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM3Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==4 && PWM4Apin!=99 && ExtCurrentConfig[PWM4Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM4Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==4 && PWM4Bpin!=99 && ExtCurrentConfig[PWM4Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM4Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==5 && PWM5Apin!=99 && ExtCurrentConfig[PWM5Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM5Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==5 && PWM5Bpin!=99 && ExtCurrentConfig[PWM5Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM5Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==6 && PWM6Apin!=99 && ExtCurrentConfig[PWM6Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM6Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==6 && PWM6Bpin!=99 && ExtCurrentConfig[PWM6Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM6Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==7 && PWM7Apin!=99 && ExtCurrentConfig[PWM7Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM7Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==7 && PWM7Bpin!=99 && ExtCurrentConfig[PWM7Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM7Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
#ifdef rp2350
|
|
if(slice==8 && PWM8Apin!=99 && ExtCurrentConfig[PWM8Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM8Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==8 && PWM8Bpin!=99 && ExtCurrentConfig[PWM8Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM8Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==9 && PWM9Apin!=99 && ExtCurrentConfig[PWM9Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM9Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==9 && PWM9Bpin!=99 && ExtCurrentConfig[PWM9Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM9Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==10 && PWM10Apin!=99 && ExtCurrentConfig[PWM10Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM10Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==10 && PWM10Bpin!=99 && ExtCurrentConfig[PWM10Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM10Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==11 && PWM11Apin!=99 && ExtCurrentConfig[PWM11Apin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM11Apin,EXT_NOT_CONFIG,0);
|
|
}
|
|
if(slice==11 && PWM11Bpin!=99 && ExtCurrentConfig[PWM11Bpin] < EXT_BOOT_RESERVED){
|
|
ExtCfg(PWM11Bpin,EXT_NOT_CONFIG,0);
|
|
}
|
|
#endif
|
|
pwm_set_enabled(slice, false);
|
|
}
|
|
#ifndef PICOMITEVGA
|
|
#ifndef PICOCALC
|
|
void setBacklight(int level, int setfrequency){
|
|
if(((Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE<BufferedPanel ) || (Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE<VIRTUAL)) && Option.DISPLAY_BL){
|
|
MMFLOAT frequency=setfrequency ? (MMFLOAT)setfrequency : (Option.DISPLAY_TYPE==ILI9488W ? 1000.0 : 50000.0);
|
|
int wrap=(Option.CPU_Speed*1000)/frequency;
|
|
int high=(int)((MMFLOAT)Option.CPU_Speed/frequency*level*10.0);
|
|
int div=1;
|
|
while(wrap>65535){
|
|
wrap>>=1;
|
|
if(level>=0.0)high>>=1;
|
|
div<<=1;
|
|
}
|
|
wrap--;
|
|
if(div!=1)pwm_set_clkdiv(BacklightSlice,(float)div);
|
|
pwm_set_wrap(BacklightSlice, wrap);
|
|
pwm_set_chan_level(BacklightSlice, BacklightChannel, high);
|
|
} else if(Option.DISPLAY_TYPE<=I2C_PANEL){
|
|
level*=255;
|
|
level/=100;
|
|
I2C_Send_Command(0x81);//SETCONTRAST
|
|
I2C_Send_Command((uint8_t)level);
|
|
} else if(Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE<VIRTUAL){
|
|
SetBacklightSSD1963(level);
|
|
} else if(Option.DISPLAY_TYPE==SSD1306SPI){
|
|
level*=255;
|
|
level/=100;
|
|
spi_write_command(0x81);//SETCONTRAST
|
|
spi_write_command((uint8_t)level);
|
|
}
|
|
#else
|
|
void setBacklight(int level){//STM32: i2c reg is REG_ID_BKL(0x05)
|
|
//level is 0-100%
|
|
level*=255;
|
|
level/=100;
|
|
I2C_Send_RegData(0x1f,0x05,(uint8_t)level);
|
|
#endif
|
|
}
|
|
/* @endcond */
|
|
void MIPS16 cmd_backlight(void){
|
|
getargs(&cmdline,3,(unsigned char *)",");
|
|
int level=getint(argv[0],0,100);
|
|
int frequency=0;
|
|
#ifndef PICOCALC
|
|
if(((Option.DISPLAY_TYPE>I2C_PANEL && Option.DISPLAY_TYPE<BufferedPanel ) || (Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE<VIRTUAL)) && Option.DISPLAY_BL){
|
|
} else if(Option.DISPLAY_TYPE<=I2C_PANEL){
|
|
} else if(Option.DISPLAY_TYPE>=SSDPANEL && Option.DISPLAY_TYPE<VIRTUAL){
|
|
} else if(Option.DISPLAY_TYPE==SSD1306SPI){
|
|
} else error("Backlight not set up");
|
|
#endif
|
|
if(argc==3){
|
|
if(checkstring(argv[2],(unsigned char *)"DEFAULT")){
|
|
Option.BackLightLevel=level;
|
|
SaveOptions();
|
|
} else {
|
|
frequency=getint(argv[2],100,100000);
|
|
}
|
|
}
|
|
#ifndef PICOCALC
|
|
setBacklight(level, frequency);
|
|
#else
|
|
setBacklight(level);
|
|
#endif
|
|
}
|
|
#endif
|
|
void MIPS16 cmd_Servo(void){
|
|
unsigned char *tp;
|
|
int div=1, high1=0, high2=0;
|
|
MMFLOAT duty1=-1.0, duty2=-1.0;
|
|
getargs(&cmdline,5,(unsigned char *)",");
|
|
if(!(argc>=3))error("Syntax");
|
|
int CPU_Speed=Option.CPU_Speed;
|
|
#ifdef rp2350
|
|
int slice=getint(argv[0],0,rp2350a ? 7:11);
|
|
if(slice==0 && ExtCurrentConfig[FAST_TIMER_PIN]==EXT_FAST_TIMER)error("Channel in use for fast frequency");
|
|
#else
|
|
int slice=getint(argv[0],0,7);
|
|
#endif
|
|
if(slice==BacklightSlice)error("Channel in use for backlight");
|
|
if(slice==Option.AUDIO_SLICE)error("Channel in use for Audio");
|
|
if(slice==CameraSlice)error("Channel in use for Camera");
|
|
if((tp=checkstring(argv[2],(unsigned char *)"OFF"))){
|
|
PWMoff(slice);
|
|
if(slice==0)slice0=0;
|
|
if(slice==1)slice1=0;
|
|
if(slice==2)slice2=0;
|
|
if(slice==3)slice3=0;
|
|
if(slice==4)slice4=0;
|
|
if(slice==5)slice5=0;
|
|
if(slice==6)slice6=0;
|
|
if(slice==7)slice7=0;
|
|
#ifdef rp2350
|
|
if(slice==8)slice8=0;
|
|
if(slice==9)slice9=0;
|
|
if(slice==10)slice10=0;
|
|
if(slice==11)slice11=0;
|
|
#endif
|
|
return;
|
|
}
|
|
MMFLOAT frequency=50.0;
|
|
if(*argv[2]){
|
|
duty1=getnumber(argv[2]);
|
|
if(duty1>120.0 || duty1<-20.0)error("Syntax");
|
|
duty1=5.0+duty1*0.05;
|
|
}
|
|
if(argc>=5 && *argv[4]){
|
|
duty2=getnumber(argv[4]);
|
|
if(duty2>120.0 || duty2<-20.0)error("Syntax");
|
|
duty2=5.0+duty2*0.05;
|
|
}
|
|
int wrap=(CPU_Speed*1000)/frequency;
|
|
if(duty1>=0.0)high1=(int)((MMFLOAT)CPU_Speed/frequency*duty1*10.0);
|
|
if(duty2>=0.0)high2=(int)((MMFLOAT)CPU_Speed/frequency*duty2*10.0);
|
|
while(wrap>65535){
|
|
wrap>>=1;
|
|
if(duty1>=0.0)high1>>=1;
|
|
if(duty2>=0.0)high2>>=1;
|
|
div<<=1;
|
|
}
|
|
if(div>256)error("Invalid frequency");
|
|
wrap--;
|
|
if(high1)high1--;
|
|
if(high2)high2--;
|
|
pwm_set_clkdiv(slice,(float)div);
|
|
pwm_set_wrap(slice, wrap);
|
|
pwm_set_output_polarity(slice,false,false);
|
|
pwm_set_phase_correct(slice,false);
|
|
set_PWM(slice,duty1,duty2,high1,high2, 0);
|
|
}
|
|
void MIPS16 cmd_pwm(void){
|
|
unsigned char *tp;
|
|
if((tp=checkstring(cmdline, (unsigned char *)"SYNC"))) {
|
|
MMFLOAT count0=-1.0,count1=-1.0,count2=-1.0,count3=-1.0,count4=-1.0,count5=-1.0,count6=-1.0,count7=-1.0;
|
|
#ifdef rp2350
|
|
MMFLOAT count8=-1.0,count9=-1.0,count10=-1.0,count11=-1.0;
|
|
getargs(&tp,23,(unsigned char *)",");
|
|
#else
|
|
getargs(&tp,15,(unsigned char *)",");
|
|
#endif
|
|
if(argc>=1){count0=getnumber(argv[0]);
|
|
if((count0<0.0 || count0>100.0) && count0!=-1.0)error("Syntax");}
|
|
if(argc>=3 && *argv[2]){count1=getnumber(argv[2]);
|
|
if((count1<0.0 || count1>100.0) && count1!=-1.0)error("Syntax");}
|
|
if(argc>=5 && *argv[4]){count2=getnumber(argv[4]);
|
|
if((count2<0.0 || count2>100.0) && count2!=-1.0)error("Syntax");}
|
|
if(argc>=7 && *argv[6]){count3=getnumber(argv[6]);
|
|
if((count3<0.0 || count3>100.0) && count3!=-1.0)error("Syntax");}
|
|
if(argc>=9 && *argv[8]){count4=getnumber(argv[8]);
|
|
if((count4<0.0 || count4>100.0) && count4!=-1.0)error("Syntax");}
|
|
if(argc>=11 && *argv[10]){count5=getnumber(argv[10]);
|
|
if((count5<0.0 || count5>100.0) && count5!=-1.0)error("Syntax");}
|
|
if(argc>=13 && *argv[12]){count6=getnumber(argv[12]);
|
|
if((count6<0.0 || count6>100.0) && count6!=-1.0)error("Syntax");}
|
|
#ifdef rp2350
|
|
if(argc>=15 && *argv[14]){count7=getnumber(argv[14]);
|
|
if((count7<0.0 || count7>100.0) && count7!=-1.0)error("Syntax");}
|
|
if(argc>=17 && *argv[16]){count8=getnumber(argv[16]);
|
|
if((count8<0.0 || count8>100.0) && count8!=-1.0)error("Syntax");}
|
|
if(argc>=19 && *argv[18]){count9=getnumber(argv[18]);
|
|
if((count9<0.0 || count9>100.0) && count9!=-1.0)error("Syntax");}
|
|
if(argc>=21 && *argv[20]){count10=getnumber(argv[20]);
|
|
if((count10<0.0 || count10>100.0) && count10!=-1.0)error("Syntax");}
|
|
if(argc==23 && *argv[22]){count11=getnumber(argv[22]);
|
|
if((count11<0.0 || count11>100.0) && count11!=-1.0)error("Syntax");}
|
|
#else
|
|
if(argc==15 && *argv[14]){count7=getnumber(argv[14]);
|
|
if((count7<0.0 || count7>100.0) && count7!=-1.0)error("Syntax");}
|
|
#endif
|
|
|
|
int enabled=0;
|
|
if(slice0 || Option.AUDIO_SLICE ==0 || BacklightSlice==0 || CameraSlice==0){
|
|
enabled |=1;
|
|
if(!(Option.AUDIO_SLICE ==0 || BacklightSlice==0 || CameraSlice==0 || count0<0.0)){
|
|
pwm_set_enabled(0,false);
|
|
count0=(MMFLOAT)pwm_hw->slice[0].top * (100.0-count0) / 100.0;
|
|
pwm_set_counter(0,(int)count0);
|
|
}
|
|
}
|
|
if(slice1 || Option.AUDIO_SLICE ==1 || BacklightSlice==1 || CameraSlice==1){
|
|
enabled |=2;
|
|
if(!(Option.AUDIO_SLICE ==1 || BacklightSlice==1 || CameraSlice==1 || count1<0.0)){
|
|
pwm_set_enabled(1,false);
|
|
count1=(MMFLOAT)pwm_hw->slice[1].top * (100.0-count1) / 100.0;
|
|
pwm_set_counter(1,count1);
|
|
}
|
|
}
|
|
if(slice2 || Option.AUDIO_SLICE ==2 || BacklightSlice==2 || CameraSlice==2){
|
|
enabled |=4;
|
|
if(!(Option.AUDIO_SLICE ==2 || BacklightSlice==2 || CameraSlice==2 || count2<0.0)){
|
|
pwm_set_enabled(2,false);
|
|
count2=(MMFLOAT)pwm_hw->slice[2].top * (100.0-count2) / 100.0;
|
|
pwm_set_counter(2,count2);
|
|
}
|
|
}
|
|
if(slice3 || Option.AUDIO_SLICE ==3 || BacklightSlice==3 || CameraSlice==3){
|
|
enabled |=8;
|
|
if(!(Option.AUDIO_SLICE ==3 || BacklightSlice==3 || CameraSlice==3 || count3<0.0)){
|
|
pwm_set_enabled(3,false);
|
|
count3=(MMFLOAT)pwm_hw->slice[3].top * (100.0-count3) / 100.0;
|
|
pwm_set_counter(3,count3);
|
|
}
|
|
}
|
|
if(slice4 || Option.AUDIO_SLICE ==4 || BacklightSlice==4 || CameraSlice==4){
|
|
enabled |=16;
|
|
if(!(Option.AUDIO_SLICE ==4 || BacklightSlice==4 || CameraSlice==4 || count4<0.0)){
|
|
pwm_set_enabled(4,false);
|
|
count4=(MMFLOAT)pwm_hw->slice[4].top * (100.0-count4) / 100.0;
|
|
pwm_set_counter(4,count4);
|
|
}
|
|
}
|
|
if(slice5 || Option.AUDIO_SLICE ==5 || BacklightSlice==5 || CameraSlice==5){
|
|
enabled |=32;
|
|
if(!(Option.AUDIO_SLICE ==5 || BacklightSlice==5 || CameraSlice==5 || count5<0.0)){
|
|
pwm_set_enabled(5,false);
|
|
count5=(MMFLOAT)pwm_hw->slice[5].top * (100.0-count5) / 100.0;
|
|
pwm_set_counter(5,count5);
|
|
}
|
|
}
|
|
if(slice6 || Option.AUDIO_SLICE ==6 || BacklightSlice==6 || CameraSlice==6){
|
|
enabled |=64;
|
|
if(!(Option.AUDIO_SLICE ==6 || BacklightSlice==6 || CameraSlice==6 || count6<0.0)){
|
|
pwm_set_enabled(6,false);
|
|
count6=(MMFLOAT)pwm_hw->slice[6].top * (100.0-count6) / 100.0;
|
|
pwm_set_counter(6,count6);
|
|
}
|
|
}
|
|
if(slice7 || Option.AUDIO_SLICE ==7 || BacklightSlice==7 || CameraSlice==7){
|
|
enabled |=128;
|
|
if(!(Option.AUDIO_SLICE ==7 || BacklightSlice==7 || CameraSlice==7 || count7<0.0)){
|
|
pwm_set_enabled(7,false);
|
|
count7=(MMFLOAT)pwm_hw->slice[7].top * (100.0-count7) / 100.0;
|
|
pwm_set_counter(7,count7);
|
|
}
|
|
}
|
|
#ifdef rp2350
|
|
if(slice8 || Option.AUDIO_SLICE ==8 || BacklightSlice==8 || CameraSlice==8){
|
|
enabled |=256;
|
|
if(!(Option.AUDIO_SLICE ==8 || BacklightSlice==8 || CameraSlice==8 || count8<0.0)){
|
|
pwm_set_enabled(8,false);
|
|
count8=(MMFLOAT)pwm_hw->slice[8].top * (100.0-count8) / 100.0;
|
|
pwm_set_counter(8,count8);
|
|
}
|
|
}
|
|
if(slice9 || Option.AUDIO_SLICE ==9 || BacklightSlice==9 || CameraSlice==9){
|
|
enabled |=512;
|
|
if(!(Option.AUDIO_SLICE ==9 || BacklightSlice==9 || CameraSlice==9 || count9<0.0)){
|
|
pwm_set_enabled(9,false);
|
|
count9=(MMFLOAT)pwm_hw->slice[9].top * (100.0-count9) / 100.0;
|
|
pwm_set_counter(9,count9);
|
|
}
|
|
}
|
|
if(slice10 || Option.AUDIO_SLICE ==10 || BacklightSlice==10 || CameraSlice==10){
|
|
enabled |=1024;
|
|
if(!(Option.AUDIO_SLICE ==10 || BacklightSlice==10 || CameraSlice==10 || count10<0.0)){
|
|
pwm_set_enabled(10,false);
|
|
count10=(MMFLOAT)pwm_hw->slice[10].top * (100.0-count10) / 100.0;
|
|
pwm_set_counter(10,count10);
|
|
}
|
|
}
|
|
if(slice11 || Option.AUDIO_SLICE ==11 || BacklightSlice==11 || CameraSlice==11){
|
|
enabled |=2048;
|
|
if(!(Option.AUDIO_SLICE ==11 || BacklightSlice==11 || CameraSlice==11 || count11<0.0)){
|
|
pwm_set_enabled(11,false);
|
|
count11=(MMFLOAT)pwm_hw->slice[11].top * (100.0-count11) / 100.0;
|
|
pwm_set_counter(11,count11);
|
|
}
|
|
}
|
|
#endif
|
|
pwm_hw->en=enabled;
|
|
return;
|
|
}
|
|
int div=1, high1=0, high2=0;
|
|
int phase1=0,phase2=0;
|
|
MMFLOAT duty1=-1.0, duty2=-1.0;
|
|
getargs(&cmdline,11,(unsigned char *)",");
|
|
if(!(argc>=3))error("Syntax");
|
|
int CPU_Speed=Option.CPU_Speed;
|
|
#ifdef rp2350
|
|
int slice=getint(argv[0],0,rp2350a ? 7:11);
|
|
if(slice==0 && ExtCurrentConfig[FAST_TIMER_PIN]==EXT_FAST_TIMER)error("Channel in use for fast frequency");
|
|
#else
|
|
int slice=getint(argv[0],0,7);
|
|
#endif
|
|
if(slice==BacklightSlice)error("Channel in use for backlight");
|
|
if(slice==Option.AUDIO_SLICE)error("Channel in use for Audio");
|
|
if(slice==CameraSlice)error("Channel in use for Camera");
|
|
if((tp=checkstring(argv[2],(unsigned char *)"OFF"))){
|
|
PWMoff(slice);
|
|
if(slice==0)slice0=0;
|
|
if(slice==1)slice1=0;
|
|
if(slice==2)slice2=0;
|
|
if(slice==3)slice3=0;
|
|
if(slice==4)slice4=0;
|
|
if(slice==5)slice5=0;
|
|
if(slice==6)slice6=0;
|
|
if(slice==7)slice7=0;
|
|
#ifdef rp2350
|
|
if(slice==8)slice8=0;
|
|
if(slice==9)slice9=0;
|
|
if(slice==10)slice10=0;
|
|
if(slice==11)slice11=0;
|
|
#endif
|
|
return;
|
|
}
|
|
if(!(argc>=5))error("Syntax");
|
|
int delaystart=0;
|
|
int phase=1;
|
|
if(argc>=9 && *argv[8])phase+=getint(argv[8],0,1);
|
|
if(argc==11)delaystart=getint(argv[10],0,1);
|
|
MMFLOAT frequency=getnumber(argv[2])*phase;
|
|
if(frequency>(MMFLOAT)(CPU_Speed>>2)*1000.0)error("Invalid frequency");
|
|
if(*argv[4]){
|
|
duty1=getnumber(argv[4]);
|
|
if(duty1>100.0 || duty1<-100.0)error("Syntax");
|
|
if(duty1<0){
|
|
duty1=-duty1;
|
|
phase1=1;
|
|
}
|
|
}
|
|
if(argc>=7 && *argv[6]){
|
|
duty2=getnumber(argv[6]);
|
|
if(duty2>100.0 || duty2<-100.0)error("Syntax");
|
|
if(duty2<0){
|
|
duty2=-duty2;
|
|
phase2=1;
|
|
}
|
|
}
|
|
int wrap=(CPU_Speed*1000)/frequency;
|
|
if(duty1>=0.0)high1=(int)((MMFLOAT)CPU_Speed/frequency*duty1*10.0);
|
|
if(duty2>=0.0)high2=(int)((MMFLOAT)CPU_Speed/frequency*duty2*10.0);
|
|
while(wrap>65535){
|
|
wrap>>=1;
|
|
if(duty1>=0.0)high1>>=1;
|
|
if(duty2>=0.0)high2>>=1;
|
|
div<<=1;
|
|
}
|
|
if(div>256)error("Invalid frequency");
|
|
wrap--;
|
|
if(high1)high1--;
|
|
if(high2)high2--;
|
|
pwm_set_clkdiv(slice,(float)div);
|
|
pwm_set_wrap(slice, wrap);
|
|
pwm_set_output_polarity(slice,phase1,phase2);
|
|
pwm_set_phase_correct(slice,(phase==2? true : false));
|
|
set_PWM(slice,duty1,duty2,high1,high2, delaystart);
|
|
}
|
|
|
|
|
|
/****************************************************************************************************************************
|
|
The KEYPAD command
|
|
*****************************************************************************************************************************/
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
static char keypad_pins[8];
|
|
MMFLOAT *KeypadVar;
|
|
unsigned char *KeypadInterrupt = NULL;
|
|
void KeypadClose(void);
|
|
/* @endcond */
|
|
|
|
void cmd_keypad(void) {
|
|
int i, j, code;
|
|
|
|
if(checkstring(cmdline, (unsigned char *)"CLOSE"))
|
|
KeypadClose();
|
|
else {
|
|
getargs(&cmdline, 19, (unsigned char *)",");
|
|
if(argc%2 == 0 || argc < 17) error("Invalid syntax");
|
|
if(KeypadInterrupt != NULL) error("Already open");
|
|
KeypadVar = findvar(argv[0], V_FIND);
|
|
if(g_vartbl[g_VarIndex].type & T_CONST) error("Cannot change a constant");
|
|
if(!(g_vartbl[g_VarIndex].type & T_NBR)) error("Floating point variable required");
|
|
InterruptUsed = true;
|
|
KeypadInterrupt = GetIntAddress(argv[2]); // get the interrupt location
|
|
for(i = 0; i < 8; i++) {
|
|
if(i == 7 && argc < 19) {
|
|
keypad_pins[i] = 0;
|
|
break;
|
|
}
|
|
code=0;
|
|
if(!(code=codecheck(argv[(i + 2) * 2])))argv[(i + 2) * 2]+=2;
|
|
j = getinteger(argv[(i + 2) * 2]);
|
|
if(!code)j=codemap(j);
|
|
if(ExtCurrentConfig[j] >= EXT_COM_RESERVED) error("Pin %/| is in use",j,j);
|
|
// if(i < 4) {
|
|
ExtCfg(j, EXT_DIG_IN, ODCSET);
|
|
ExtCfg(j, EXT_COM_RESERVED, 0);
|
|
keypad_pins[i] = j;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
void KeypadClose(void) {
|
|
int i;
|
|
if(KeypadInterrupt == NULL) return;
|
|
for(i = 0; i < 8; i++) {
|
|
if(keypad_pins[i]) {
|
|
ExtCfg(keypad_pins[i], EXT_NOT_CONFIG, 0); // all set to unconfigured
|
|
}
|
|
}
|
|
KeypadInterrupt = NULL;
|
|
}
|
|
|
|
|
|
int KeypadCheck(void) {
|
|
static unsigned char count = 0, keydown = false;
|
|
int i, j;
|
|
const char PadLookup[16] = { 1, 2, 3, 20, 4, 5, 6, 21, 7, 8, 9, 22, 10, 0, 11, 23 };
|
|
|
|
if(count++ % 64) return false; // only check every 64 loops through the interrupt processor
|
|
|
|
for(j = 4; j < 8; j++) { // j controls the pull down pins
|
|
if(keypad_pins[j]) { // we might just have 3 pull down pins
|
|
PinSetBit(keypad_pins[j], ODCCLR); // pull it low
|
|
for(i = 0; i < 4; i++) { // i is the row sense inputs
|
|
if(PinRead((unsigned char)keypad_pins[i]) == 0) { // if it is low we have found a keypress
|
|
if(keydown) goto exitcheck; // we have already reported this, so just exit
|
|
uSec(40 * 1000); // wait 40mS and check again
|
|
if(PinRead((unsigned char)keypad_pins[i]) != 0) goto exitcheck;// must be contact bounce if it is now high
|
|
*KeypadVar = PadLookup[(i << 2) | (j - 4)]; // lookup the key value and set the variable
|
|
PinSetBit(keypad_pins[j], ODCSET);
|
|
keydown = true; // record that we know that the key is down
|
|
return true; // and tell the interrupt processor that we are good to go
|
|
}
|
|
}
|
|
PinSetBit(keypad_pins[j], ODCSET); // wasn't this pin, clear the pulldown
|
|
}
|
|
}
|
|
keydown = false; // no key down, record the fact
|
|
return false;
|
|
|
|
exitcheck:
|
|
PinSetBit(keypad_pins[j], ODCSET);
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
/****************************************************************************************************************************
|
|
The LCD command
|
|
*****************************************************************************************************************************/
|
|
|
|
void LCD_Nibble(int Data, int Flag, int Wait_uSec);
|
|
void LCD_Byte(int Data, int Flag, int Wait_uSec);
|
|
void LcdPinSet(int pin, int val);
|
|
static char lcd_pins[6];
|
|
/* @endcond */
|
|
|
|
void cmd_lcd(void)
|
|
{
|
|
unsigned char *p;
|
|
int i, j, code;
|
|
|
|
if((p = checkstring(cmdline, (unsigned char *)"INIT"))) {
|
|
getargs(&p, 11, (unsigned char *)",");
|
|
if(argc != 11) error("Invalid syntax");
|
|
if(*lcd_pins) error("Already open");
|
|
for(i = 0; i < 6; i++) {
|
|
code=0;
|
|
if(!(code=codecheck(argv[i * 2])))argv[i * 2]+=2;
|
|
lcd_pins[i] = getinteger(argv[i * 2]);
|
|
if(!code)lcd_pins[i]=codemap(lcd_pins[i]);
|
|
if(ExtCurrentConfig[(int)lcd_pins[i]] >= EXT_COM_RESERVED) error("Pin %/| is in use",lcd_pins[i],lcd_pins[i]);
|
|
ExtCfg(lcd_pins[i], EXT_DIG_OUT, 0);
|
|
ExtCfg(lcd_pins[i], EXT_COM_RESERVED, 0);
|
|
}
|
|
LCD_Nibble(0b0011, 0, 5000); // reset
|
|
LCD_Nibble(0b0011, 0, 5000); // reset
|
|
LCD_Nibble(0b0011, 0, 5000); // reset
|
|
LCD_Nibble(0b0010, 0, 2000); // 4 bit mode
|
|
LCD_Byte(0b00101100, 0, 600); // 4 bits, 2 lines
|
|
LCD_Byte(0b00001100, 0, 600); // display on, no cursor
|
|
LCD_Byte(0b00000110, 0, 600); // increment on write
|
|
LCD_Byte(0b00000001, 0, 3000); // clear the display
|
|
return;
|
|
}
|
|
|
|
if(!*lcd_pins) error("Not open");
|
|
if(checkstring(cmdline, (unsigned char *)"CLOSE")) {
|
|
for(i = 0; i < 6; i++) {
|
|
ExtCfg(lcd_pins[i], EXT_NOT_CONFIG, 0); // all set to unconfigured
|
|
ExtSet(lcd_pins[i], 0); // all outputs (when set) default to low
|
|
*lcd_pins = 0;
|
|
}
|
|
} else if(checkstring(cmdline, (unsigned char *)"CLEAR")) { // clear the display
|
|
LCD_Byte(0b00000001, 0, 3000);
|
|
} else if((p = checkstring(cmdline, (unsigned char *)"CMD")) || (p = checkstring(cmdline, (unsigned char *)"DATA"))) { // send a command or data
|
|
getargs(&p, MAX_ARG_COUNT * 2, (unsigned char *)",");
|
|
for(i = 0; i < argc; i += 2) {
|
|
j = getint(argv[i], 0, 255);
|
|
LCD_Byte(j, toupper(*cmdline) == 'D', 0);
|
|
}
|
|
} else {
|
|
const char linestart[4] = {0, 64, 20, 84};
|
|
int center, pos;
|
|
|
|
getargs(&cmdline, 5, (unsigned char *)",");
|
|
if(argc != 5) error("Invalid syntax");
|
|
i = getint(argv[0], 1, 4);
|
|
pos = 1;
|
|
if(checkstring(argv[2], (unsigned char *)"C8"))
|
|
center = 8;
|
|
else if(checkstring(argv[2], (unsigned char *)"C16"))
|
|
center = 16;
|
|
else if(checkstring(argv[2], (unsigned char *)"C20"))
|
|
center = 20;
|
|
else if(checkstring(argv[2], (unsigned char *)"C40"))
|
|
center = 40;
|
|
else {
|
|
center = 0;
|
|
pos = getint(argv[2], 1, 256);
|
|
}
|
|
p = getstring(argv[4]); // returns an MMBasic string
|
|
i = 128 + linestart[i - 1] + (pos - 1);
|
|
LCD_Byte(i, 0, 600);
|
|
for(j = 0; j < (center - *p) / 2; j++) {
|
|
LCD_Byte(' ', 1, 0);
|
|
}
|
|
for(i = 1; i <= *p; i++) {
|
|
LCD_Byte(p[i], 1, 0);
|
|
j++;
|
|
}
|
|
for(; j < center; j++) {
|
|
LCD_Byte(' ', 1, 0);
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
void LCD_Nibble(int Data, int Flag, int Wait_uSec) {
|
|
int i;
|
|
LcdPinSet(lcd_pins[4], Flag);
|
|
for(i = 0; i < 4; i++)
|
|
LcdPinSet(lcd_pins[i], (Data >> i) & 1);
|
|
LcdPinSet(lcd_pins[5], 1); uSec(250); LcdPinSet(lcd_pins[5], 0);
|
|
if(Wait_uSec)
|
|
uSec(Wait_uSec);
|
|
else
|
|
uSec(250);
|
|
}
|
|
|
|
|
|
void LCD_Byte(int Data, int Flag, int Wait_uSec) {
|
|
LCD_Nibble(Data/16, Flag, 0);
|
|
LCD_Nibble(Data, Flag, Wait_uSec);
|
|
}
|
|
|
|
|
|
void LcdPinSet(int pin, int val) {
|
|
PinSetBit(pin, val ? LATSET : LATCLR);
|
|
}
|
|
int64_t DHmem(int pin){
|
|
int timeout = 400;
|
|
long long int r;
|
|
int i;
|
|
writeusclock(0);
|
|
PinSetBit(pin, CNPUSET);
|
|
PinSetBit(pin, TRISSET);
|
|
uSec(5);
|
|
// wait for the DHT22 to pull the pin low and return it high then take it low again
|
|
while(PinRead(pin)) if(readusclock() > timeout) goto error_exit;
|
|
while(!PinRead(pin)) if(readusclock() > timeout) goto error_exit;
|
|
while(PinRead(pin)) if(readusclock() > timeout) goto error_exit;
|
|
// PInt(readusclock());PRet();
|
|
|
|
// now we wait for the pin to go high and measure how long it stays high (> 50uS is a one bit, < 50uS is a zero bit)
|
|
for(r = i = 0; i < 40; i++) {
|
|
timeout=400;
|
|
while(!PinRead(pin)) if(readusclock() > timeout) goto error_exit;
|
|
timeout=400;writeusclock(0);
|
|
while(PinRead(pin)) if(readusclock() > timeout) goto error_exit;
|
|
r <<= 1;
|
|
r |= (readusclock() > 50);
|
|
}
|
|
return r;
|
|
error_exit:
|
|
return -1;
|
|
|
|
}
|
|
/* @endcond */
|
|
|
|
void cmd_DHT22(void) {
|
|
int pin;
|
|
union colourmap {
|
|
unsigned char dhtbytes[8];
|
|
long long int r;
|
|
} dht;
|
|
// long long int r;
|
|
int dht11=0;
|
|
MMFLOAT *temp, *humid;
|
|
|
|
getargs(&cmdline, 7, (unsigned char *)",");
|
|
if(!(argc == 5 || argc == 7)) error("Incorrect number of arguments");
|
|
|
|
// get the two variables
|
|
temp = findvar(argv[2], V_FIND);
|
|
if(!(g_vartbl[g_VarIndex].type & T_NBR)) error("Invalid variable");
|
|
humid = findvar(argv[4], V_FIND);
|
|
if(!(g_vartbl[g_VarIndex].type & T_NBR)) error("Invalid variable");
|
|
|
|
// get the pin number and set it up
|
|
// get the pin number and set it up
|
|
char code;
|
|
if(!(code=codecheck(argv[0])))argv[0]+=2;
|
|
pin = getinteger(argv[0]);
|
|
if(!code)pin=codemap(pin);
|
|
if(IsInvalidPin(pin)) error("Invalid pin ");
|
|
if(ExtCurrentConfig[pin] != EXT_NOT_CONFIG) error("Pin %/| is in use",pin,pin);
|
|
if(argc==7){
|
|
dht11=getint(argv[6],0,1);
|
|
}
|
|
ExtCfg(pin, EXT_DIG_OUT, 0);
|
|
|
|
// pulse the pin low for 1.5mS
|
|
uSec(1500+dht11*18000);
|
|
// we have all 40 bits
|
|
// first validate against the checksum
|
|
if((dht.r=DHmem(pin))==-1) goto error_exit;
|
|
if((uint8_t)(dht.dhtbytes[4]+dht.dhtbytes[3]+dht.dhtbytes[2]+dht.dhtbytes[1])!=dht.dhtbytes[0])goto error_exit;
|
|
// if( ( (uint8_t)( ((r >> 8) & 0xff) + ((r >> 16) & 0xff) + ((r >> 24) & 0xff) + ((r >> 32) & 0xff) ) & 0xff) != (r & 0xff)) goto error_exit; // returning temperature
|
|
if(dht11==0){
|
|
*temp = (MMFLOAT)((dht.r >> 8) &0x7fff) / 10.0; // get the temperature
|
|
if((dht.r >> 8) &0x8000) *temp = -*temp; // the top bit is the sign
|
|
*humid = (MMFLOAT)(dht.r >> 24) / 10.0; // get the humidity
|
|
} else {
|
|
*temp = (MMFLOAT)(dht.dhtbytes[2])+(MMFLOAT)(dht.dhtbytes[1])/10.0; // get the temperature
|
|
*humid =(MMFLOAT)(dht.dhtbytes[4])+(MMFLOAT)(dht.dhtbytes[3])/10.0; // get the humidity
|
|
}
|
|
goto normal_exit;
|
|
|
|
error_exit:
|
|
*temp = *humid = 1000.0; // an obviously incorrect reading
|
|
|
|
normal_exit:
|
|
ExtCfg(pin, EXT_NOT_CONFIG, 0);
|
|
PinSetBit(pin, LATCLR);
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
void __not_in_flash_func(WS2812e)(int gppin, int T1H, int T1L, int T0H, int T0L, int nbr, char *p){
|
|
for(int i=0;i<nbr;i++){
|
|
for(int j=0;j<8;j++){
|
|
if(*p & 1){
|
|
gpio_put(gppin,true);
|
|
shortpause(T1H);
|
|
gpio_put(gppin,false);
|
|
shortpause(T1L);
|
|
} else {
|
|
gpio_put(gppin,true);
|
|
shortpause(T0H);
|
|
gpio_put(gppin,false);
|
|
shortpause(T0L);
|
|
}
|
|
*p>>=1;
|
|
}
|
|
p++;
|
|
}
|
|
}
|
|
/* @endcond */
|
|
void fun_dev(void){
|
|
unsigned char *tp=NULL;
|
|
tp = checkstring(ep, (unsigned char *)"WII");
|
|
if(tp==NULL)tp = checkstring(ep, (unsigned char *)"CLASSIC");
|
|
if(tp){
|
|
// int ax; //classic left x
|
|
// int ay; //classic left y
|
|
// int az; //classic centre
|
|
// int Z; //classic right x
|
|
// int C; //classic right y
|
|
// int L; //classic left analog
|
|
// int R; //classic right analog
|
|
// unsigned short x0; //classic buttons
|
|
getargs(&tp,1,(unsigned char *)",");
|
|
if(!classic1)error("Not open");
|
|
if(checkstring(argv[0], (unsigned char *)"LX"))iret=nunstruct[0].ax;
|
|
else if(checkstring(argv[0], (unsigned char *)"LY"))iret=nunstruct[0].ay;
|
|
else if(checkstring(argv[0], (unsigned char *)"RX"))iret=nunstruct[0].Z;
|
|
else if(checkstring(argv[0], (unsigned char *)"RY"))iret=nunstruct[0].C;
|
|
else if(checkstring(argv[0], (unsigned char *)"L"))iret=nunstruct[0].L;
|
|
else if(checkstring(argv[0], (unsigned char *)"R"))iret=nunstruct[0].R;
|
|
else if(checkstring(argv[0], (unsigned char *)"B"))iret=nunstruct[0].x0;
|
|
else if(checkstring(argv[0], (unsigned char *)"T"))iret=nunstruct[0].type;
|
|
else iret=0;
|
|
targ=T_INT;
|
|
} else if((tp=checkstring(ep,(unsigned char *)"NUNCHUCK"))){
|
|
unsigned char *p;
|
|
getargs(&tp,1,(unsigned char *)",");
|
|
p=argv[0];
|
|
if(toupper(*p)=='A'){
|
|
p++;
|
|
if(p[1]==0){
|
|
if(toupper(*p)=='X')iret=nunstruct[5].ax;
|
|
else if(toupper(*p)=='Y')iret=nunstruct[5].ay;
|
|
else if(toupper(*p)=='Z')iret=nunstruct[5].az;
|
|
else error("Syntax");
|
|
} else {
|
|
if(p[1]=='0'){
|
|
if(toupper(*p)=='X')iret=nunstruct[5].x0;
|
|
else if(toupper(*p)=='Y')iret=nunstruct[5].y0;
|
|
else if(toupper(*p)=='Z')iret=nunstruct[5].z0;
|
|
else error("Syntax");
|
|
} else if(p[1]=='1'){
|
|
if(toupper(*p)=='X')iret=nunstruct[5].x1;
|
|
else if(toupper(*p)=='Y')iret=nunstruct[5].y1;
|
|
else if(toupper(*p)=='Z')iret=nunstruct[5].z1;
|
|
else error("Syntax");
|
|
} else error("Syntax");
|
|
}
|
|
} else if(toupper(*p)=='J'){
|
|
p++;
|
|
if(p[1]==0){
|
|
if(toupper(*p)=='X')iret=nunstruct[5].x;
|
|
else if(toupper(*p)=='Y')iret=nunstruct[5].y;
|
|
} else {
|
|
if(toupper(*p)=='X'){
|
|
p++;
|
|
if(toupper(*p)=='L'){
|
|
iret=nunstruct[5].calib[9];
|
|
} else if(toupper(*p)=='C'){
|
|
iret=nunstruct[5].calib[10];
|
|
} else if(toupper(*p)=='R'){
|
|
iret=nunstruct[5].calib[8];
|
|
} else error("Syntax");
|
|
} else if(toupper(*p)=='Y'){
|
|
p++;
|
|
if(toupper(*p)=='T'){
|
|
iret=nunstruct[5].calib[11];
|
|
} else if(toupper(*p)=='C'){
|
|
iret=nunstruct[5].calib[13];
|
|
} else if(toupper(*p)=='B'){
|
|
iret=nunstruct[5].calib[12];
|
|
} else error("Syntax");
|
|
} else error("Syntax");
|
|
}
|
|
} else {
|
|
if(toupper(*p)=='Z')iret=nunstruct[5].Z;
|
|
else if(toupper(*p)=='C')iret=nunstruct[5].C;
|
|
else if(toupper(*p)=='T')iret=nunstruct[5].type;
|
|
else error("Syntax");
|
|
}
|
|
targ=T_INT;
|
|
} else if((tp=checkstring(ep,(unsigned char *)"GAMEPAD"))){
|
|
// int ax; //classic left x
|
|
// int ay; //classic left y
|
|
// int az; //classic centre
|
|
// int Z; //classic right x
|
|
// int C; //classic right y
|
|
// int L; //classic left analog
|
|
// int R; //classic right analog
|
|
// unsigned short x0; //classic buttons
|
|
getargs(&tp,3,(unsigned char *)",");
|
|
int n=getint(argv[0],1,4);
|
|
if(checkstring(argv[2], (unsigned char *)"LX"))iret=nunstruct[n].ax;
|
|
else if(checkstring(argv[2], (unsigned char *)"LY"))iret=nunstruct[n].ay;
|
|
else if(checkstring(argv[2], (unsigned char *)"RX"))iret=nunstruct[n].Z;
|
|
else if(checkstring(argv[2], (unsigned char *)"RY"))iret=nunstruct[n].C;
|
|
else if(checkstring(argv[2], (unsigned char *)"L"))iret=nunstruct[n].L;
|
|
else if(checkstring(argv[2], (unsigned char *)"R"))iret=nunstruct[n].R;
|
|
else if(checkstring(argv[2], (unsigned char *)"B"))iret=nunstruct[n].x0;
|
|
else if(checkstring(argv[2], (unsigned char *)"GX"))iret=nunstruct[n].gyro[0];
|
|
else if(checkstring(argv[2], (unsigned char *)"GY"))iret=nunstruct[n].gyro[1];
|
|
else if(checkstring(argv[2], (unsigned char *)"GZ"))iret=nunstruct[n].gyro[2];
|
|
else if(checkstring(argv[2], (unsigned char *)"AX"))iret=nunstruct[n].accs[0];
|
|
else if(checkstring(argv[2], (unsigned char *)"AY"))iret=nunstruct[n].accs[1];
|
|
else if(checkstring(argv[2], (unsigned char *)"AZ"))iret=nunstruct[n].accs[2];
|
|
else if(checkstring(argv[2], (unsigned char *)"T"))iret=nunstruct[n].type;
|
|
#ifdef USBKEYBOARD
|
|
else if(checkstring(argv[2], (unsigned char *)"RAW")){
|
|
sret=GetTempMemory(STRINGSIZE);
|
|
targ=T_STR;
|
|
Mstrcpy(sret,(unsigned char *)HID[n-1].report);
|
|
return;
|
|
}
|
|
#endif
|
|
else iret=0;
|
|
targ=T_INT;
|
|
} else if((tp=checkstring(ep,(unsigned char *)"MOUSE"))){
|
|
/* Returns data from a PS2 mouse
|
|
'funct' is a 1 letter code indicating the information to return as follows:
|
|
X returns the value of the mouse X-position
|
|
Y returns the value of the mouse Y-position
|
|
L returns the value of the left mouse button (1 if pressed)
|
|
R returns the value of the right mouse button (1 if pressed)
|
|
W returns the value of the scroll wheel mouse button (1 if pressed)
|
|
D This allows you to detect a double click of the left mouse button. The
|
|
algorithm requires that the two clicks must occur between 100 and
|
|
500 milliseconds apart. The report via MOUSE(D) is then valid for
|
|
500mSec before it times out or until it is read.
|
|
T This returns 3 if a PS2 mouse has a scroll wheel or 0 if not.*/
|
|
|
|
getargs(&tp,3,(unsigned char *)",");
|
|
int n=getint(argv[0],1,4);
|
|
if(checkstring(argv[2], (unsigned char *)"X"))iret=nunstruct[n].ax;
|
|
else if(checkstring(argv[2], (unsigned char *)"Y"))iret=nunstruct[n].ay;
|
|
else if(checkstring(argv[2], (unsigned char *)"L"))iret=nunstruct[n].L;
|
|
else if(checkstring(argv[2], (unsigned char *)"R"))iret=nunstruct[n].R;
|
|
else if(checkstring(argv[2], (unsigned char *)"M"))iret=nunstruct[n].C;
|
|
else if(checkstring(argv[2], (unsigned char *)"W"))iret=nunstruct[n].az;
|
|
else if(checkstring(argv[2], (unsigned char *)"D")){iret=nunstruct[n].Z;nunstruct[n].Z=0;}
|
|
else if(checkstring(argv[2], (unsigned char *)"T"))iret=nunstruct[n].classic[0];
|
|
else error("Syntax");
|
|
targ=T_INT;
|
|
} else error("Syntax");
|
|
|
|
}
|
|
|
|
void cmd_WS2812(void){
|
|
int64_t *dest=NULL;
|
|
uint32_t pin, red , green, blue, white, colour;
|
|
int T0H=0,T0L=0,T1H=0,T1L=0,TRST=0;
|
|
unsigned char *p;
|
|
int i, j, bit, nbr=0, colours=3;
|
|
int ticks_per_millisecond=ticks_per_second/1000;
|
|
getargs(&cmdline, 7, (unsigned char *)",");
|
|
if(argc != 7)error("Argument count");
|
|
p=argv[0];
|
|
if(toupper(*p)=='O'){
|
|
T0H=16777215 + setuptime-((7*ticks_per_millisecond)/20000) ;
|
|
T1H=16777215 + setuptime-((14*ticks_per_millisecond)/20000) ;
|
|
T0L=16777215 + setuptime-((13*ticks_per_millisecond)/20000) ;
|
|
T1L=16777215 + setuptime-((9.5*ticks_per_millisecond)/20000) ;
|
|
TRST=50;
|
|
} else if(toupper(*p)=='B'){
|
|
T0H=16777215 + setuptime-((8*ticks_per_millisecond)/20000) ;
|
|
T1H=16777215 + setuptime-((16*ticks_per_millisecond)/20000) ;
|
|
T0L=16777215 + setuptime-((14*ticks_per_millisecond)/20000) ;
|
|
T1L=16777215 + setuptime-((6.5*ticks_per_millisecond)/20000) ;
|
|
TRST=280;
|
|
} else if(toupper(*p)=='S' || toupper(*p)=='W' ){
|
|
if(toupper(*p)=='W')colours=4;
|
|
T0H=16777215 + setuptime-((6*ticks_per_millisecond)/20000) ;
|
|
T0L=16777215 + setuptime-((15*ticks_per_millisecond)/20000) ;
|
|
T1H=16777215 + setuptime-((12*ticks_per_millisecond)/20000) ;
|
|
T1L=16777215 + setuptime-((9*ticks_per_millisecond)/20000) ;
|
|
TRST=80;
|
|
} else error("Syntax");
|
|
nbr=getint(argv[4],1,256);
|
|
if(nbr>1){
|
|
parseintegerarray(argv[6], &dest, 4, 1, NULL, false);
|
|
} else {
|
|
colour=getinteger(argv[6]);
|
|
dest = (long long int *)&colour;
|
|
}
|
|
unsigned char code;
|
|
if(!(code=codecheck(argv[2])))argv[2]+=2;
|
|
pin = getinteger(argv[2]);
|
|
if(!code)pin=codemap(pin);
|
|
if(IsInvalidPin(pin)) error("Invalid pin");
|
|
int gppin=PinDef[pin].GPno;
|
|
if(!(ExtCurrentConfig[pin] == EXT_DIG_OUT || ExtCurrentConfig[pin] == EXT_NOT_CONFIG)) error("Pin %/| is not off or an output",pin,pin);
|
|
if(ExtCurrentConfig[pin] == EXT_NOT_CONFIG)ExtCfg(pin, EXT_DIG_OUT, 0);
|
|
p=GetTempMemory((nbr+1)*colours);
|
|
uint64_t endreset=time_us_64()+TRST;
|
|
for(i=0;i<nbr;i++){
|
|
green=(dest[i]>>8) & 0xFF;
|
|
red=(dest[i]>>16) & 0xFF;
|
|
blue=dest[i] & 0xFF;
|
|
if(colours==4)white=(dest[i]>>24) & 0xFF;
|
|
p[0]=0;p[1]=0;p[2]=0;
|
|
if(colours==4){p[3]=0;}
|
|
for(j=0;j<8;j++){
|
|
bit=1<<j;
|
|
if( green & (1<<(7-j)) )p[0] |= bit;
|
|
if(red & (1<<(7-j)))p[1] |= bit;
|
|
if(blue & (1<<(7-j)))p[2] |= bit;
|
|
if(colours==4){
|
|
if(white & (1<<(7-j)))p[3] |= bit;
|
|
}
|
|
}
|
|
p+=colours;
|
|
}
|
|
p-=(nbr*colours);
|
|
while(time_us_64()<endreset){}
|
|
disable_interrupts_pico();
|
|
WS2812e(gppin, T1H, T1L, T0H, T0L, nbr*colours, (char *)p);
|
|
enable_interrupts_pico();
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
void __not_in_flash_func(bitstream)(int gppin, unsigned int *data, int num){
|
|
for(int i=0;i<num;i++){
|
|
gpio_xor_mask64(gppin);
|
|
shortpause(data[i])
|
|
}
|
|
}
|
|
void __not_in_flash_func(serialtx)(int gppin, unsigned char *string, int bittime){
|
|
int mask;
|
|
int count = 0;
|
|
while(count++ < string[0]) {
|
|
systick_hw->cvr=0;
|
|
gpio_clr_mask64(gppin); // send the start bit
|
|
mask=1;
|
|
while(systick_hw->cvr>bittime){};
|
|
systick_hw->cvr=0;
|
|
for (mask=1;mask<0x100; mask<<=1) {
|
|
if(string[count] & mask) { // check the bit to send
|
|
gpio_set_mask64(gppin); // send the start bit
|
|
} else {
|
|
gpio_clr_mask64(gppin); // send the start bit
|
|
}
|
|
while(systick_hw->cvr>bittime){};
|
|
systick_hw->cvr=0;
|
|
}
|
|
gpio_set_mask64(gppin); // send the start bit
|
|
while(systick_hw->cvr>bittime){};
|
|
}
|
|
}
|
|
unsigned short FloatToUint32(MMFLOAT x) {
|
|
if(x<0 || x > 4294967295)
|
|
error("Number range");
|
|
return (x >= 0 ? (unsigned int)(x + 0.5) : (unsigned int)(x - 0.5)) ;
|
|
}
|
|
int __not_in_flash_func(serialrx)(int gppin, unsigned char *string, int timeout, int bittime, int half, int maxchars, char *termchars){
|
|
int i,c,count=0;
|
|
while(1){
|
|
while(gpio_get_all64() & gppin) { // wait for the start bit
|
|
if(readusclock() >= timeout) return -1; // return if there is a timeout
|
|
}
|
|
systick_hw->cvr=0;
|
|
while(systick_hw->cvr>half){};
|
|
systick_hw->cvr=0;
|
|
if(gpio_get_all64() & gppin) continue; // go around again if not low
|
|
c=0;
|
|
for(i = 0; i < 8; i++) {
|
|
while(systick_hw->cvr>bittime){};
|
|
systick_hw->cvr=0;
|
|
c |= (((gpio_get_all64() & gppin) ? 1 : 0) << i); // and add this bit in
|
|
}
|
|
while(systick_hw->cvr>bittime){};
|
|
if(!(gpio_get_all64() & gppin)) continue; // a framing error if not high
|
|
count++;
|
|
string[count] = c; // save the character
|
|
string[0] = count; // and update the numbers of characters in the string
|
|
if(count >= maxchars) return 2; // do we have our maximun number of characters?
|
|
if(termchars) {
|
|
for(i = 0; i < termchars[0]; i++) { // check each terminating character
|
|
if(c == termchars[i + 1]) return 3; // and exit if this character is one of them
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* @endcond */
|
|
void cmd_device(void){
|
|
unsigned char *tp;
|
|
tp = checkstring(cmdline, (unsigned char *)"WS2812");
|
|
if(tp) {
|
|
cmdline=tp;
|
|
cmd_WS2812();
|
|
return;
|
|
}
|
|
tp = checkstring(cmdline, (unsigned char *)"KEYPAD");
|
|
if(tp) {
|
|
cmdline=tp;
|
|
cmd_keypad();
|
|
return;
|
|
}
|
|
tp = checkstring(cmdline, (unsigned char *)"LCD");
|
|
if(tp) {
|
|
cmdline=tp;
|
|
cmd_lcd();
|
|
return;
|
|
}
|
|
#ifndef PICOMITEVGA
|
|
tp = checkstring(cmdline, (unsigned char *)"CAMERA");
|
|
if(tp) {
|
|
cmdline=tp;
|
|
cmd_camera();
|
|
return;
|
|
}
|
|
#endif
|
|
tp = checkstring(cmdline, (unsigned char *)"WII CLASSIC");
|
|
if(tp==NULL)tp = checkstring(cmdline, (unsigned char *)"WII");
|
|
if(tp) {
|
|
cmdline=tp;
|
|
cmd_Classic();
|
|
return;
|
|
}
|
|
tp = checkstring(cmdline, (unsigned char *)"NUNCHUCK");
|
|
if(tp) {
|
|
cmdline=tp;
|
|
cmd_Nunchuck();
|
|
return;
|
|
}
|
|
#ifdef USBKEYBOARD
|
|
tp = checkstring(cmdline, (unsigned char *)"MOUSE");
|
|
if(tp) {
|
|
cmdline=tp;
|
|
cmd_mouse();
|
|
return;
|
|
}
|
|
tp = checkstring(cmdline, (unsigned char *)"GAMEPAD");
|
|
if(tp) {
|
|
cmdline=tp;
|
|
cmd_gamepad();
|
|
return;
|
|
}
|
|
#endif
|
|
tp = checkstring(cmdline, (unsigned char *)"HUMID");
|
|
if(tp) {
|
|
cmdline=tp;
|
|
cmd_DHT22();
|
|
return;
|
|
}
|
|
tp = checkstring(cmdline, (unsigned char *)"SERIALRX");
|
|
if(tp) {
|
|
int maxchars=255;
|
|
char *termchars=NULL;
|
|
getargs(&tp, 13,(unsigned char *)",");
|
|
if(argc < 9) error("Argument count");
|
|
unsigned char code;
|
|
if(!(code=codecheck(argv[0])))argv[0]+=2;
|
|
int pin = getinteger(argv[0]);
|
|
if(!code)pin=codemap(pin);
|
|
if(IsInvalidPin(pin)) error("Invalid pin");
|
|
if(!(ExtCurrentConfig[pin] == EXT_DIG_IN || ExtCurrentConfig[pin] == EXT_NOT_CONFIG)) error("Pin %/| is not off or an input",pin,pin);
|
|
if(ExtCurrentConfig[pin] == EXT_NOT_CONFIG)ExtCfg(pin, EXT_DIG_IN, CNPUSET);
|
|
int gppin=(1<<PinDef[pin].GPno);
|
|
int baudrate=getint(argv[2],110,230400);
|
|
unsigned char *string=NULL;
|
|
string = findvar(argv[4], V_FIND);
|
|
if(!(g_vartbl[g_VarIndex].type & T_STR)) error("Invalid variable");
|
|
int timeout=getint(argv[6],1,100000)*1000;
|
|
void *status=findvar(argv[8], V_FIND);
|
|
int type=g_vartbl[g_VarIndex].type;
|
|
if(!(type & (T_NBR | T_INT))) error("Invalid variable");
|
|
if(argc>9 && *argv[10])maxchars=getint(argv[10],1,255);
|
|
if(argc==13)termchars=(char *)getstring(argv[12]);
|
|
writeusclock(0);
|
|
int bittime=16777215 + 12 - (ticks_per_second/baudrate) ;
|
|
int half = 16777215 + 12 - (ticks_per_second/(baudrate<<1)) ;
|
|
if(!(gpio_get_all64() & gppin))error("Framing error");
|
|
disable_interrupts_pico();
|
|
int istat=serialrx(gppin, string, timeout, bittime, half, maxchars, termchars);
|
|
enable_interrupts_pico();
|
|
if(type & T_INT)*(int64_t *)status=(int64_t)istat;
|
|
else *(MMFLOAT *)status=(MMFLOAT)istat;
|
|
return;
|
|
}
|
|
tp = checkstring(cmdline, (unsigned char *)"SERIALTX");
|
|
if(tp) {
|
|
// int mask;
|
|
getargs(&tp, 5,(unsigned char *)",");
|
|
if(!(argc == 5)) error("Argument count");
|
|
unsigned char code;
|
|
// int count = 0;
|
|
if(!(code=codecheck(argv[0])))argv[0]+=2;
|
|
int pin = getinteger(argv[0]);
|
|
if(!code)pin=codemap(pin);
|
|
if(IsInvalidPin(pin)) error("Invalid pin");
|
|
int gppin=(1<<PinDef[pin].GPno);
|
|
int baudrate=getint(argv[2],110,230400);
|
|
unsigned char *string=getstring(argv[4]);
|
|
if(!(ExtCurrentConfig[pin] == EXT_DIG_OUT || ExtCurrentConfig[pin] == EXT_NOT_CONFIG)) error("Pin %/| is not off or an output",pin,pin);
|
|
if(ExtCurrentConfig[pin] == EXT_NOT_CONFIG)ExtCfg(pin, EXT_DIG_OUT, 0);
|
|
gpio_set_mask64(gppin); // send the start bit
|
|
int bittime=16777215 + 12 - (ticks_per_second/baudrate) ;
|
|
disable_interrupts_pico();
|
|
serialtx(gppin,string, bittime);
|
|
enable_interrupts_pico();
|
|
return;
|
|
}
|
|
tp = checkstring(cmdline, (unsigned char *)"BITSTREAM");
|
|
if(tp) {
|
|
int i,num,size;
|
|
uint32_t pin;
|
|
int ticks_per_millisecond=ticks_per_second/1000;
|
|
MMFLOAT *a1float=NULL;
|
|
int64_t *a1int=NULL;
|
|
unsigned int *data;
|
|
getargs(&tp, 5,(unsigned char *)",");
|
|
if(!(argc == 5)) error("Argument count");
|
|
num=getint(argv[2],1,10000);
|
|
unsigned char code;
|
|
if(!(code=codecheck(argv[0])))argv[0]+=2;
|
|
pin = getinteger(argv[0]);
|
|
if(!code)pin=codemap(pin);
|
|
if(IsInvalidPin(pin)) error("Invalid pin");
|
|
int gppin=(1<<PinDef[pin].GPno);
|
|
if(!(ExtCurrentConfig[pin] == EXT_DIG_OUT || ExtCurrentConfig[pin] == EXT_NOT_CONFIG)) error("Pin %/| is not off or an output",pin,pin);
|
|
if(ExtCurrentConfig[pin] == EXT_NOT_CONFIG)ExtCfg(pin, EXT_DIG_OUT, 0);
|
|
size=parsenumberarray(argv[4],&a1float, &a1int, 3, 1, NULL, false);
|
|
if(size < num)error("Array too small");
|
|
data=GetTempMemory(num * sizeof(unsigned int));
|
|
if(a1float!=NULL){
|
|
for(i=0; i< num;i++)data[i]= FloatToUint32(*a1float++);
|
|
} else {
|
|
for(i=0; i< num;i++){
|
|
if(*a1int <0 || *a1int>67108)error("Number range");
|
|
data[i]= *a1int++ ;
|
|
}
|
|
}
|
|
for(i=0; i< num;i++){
|
|
data[i]=16777215 + setuptime-((data[i]*ticks_per_millisecond)/1000) ;
|
|
}
|
|
// data[0]+=((ticks_per_millisecond/2000)+(250000-Option.CPU_Speed)/1000);
|
|
disable_interrupts_pico();
|
|
bitstream(gppin,data,num);
|
|
enable_interrupts_pico();
|
|
return;
|
|
}
|
|
error("Syntax");
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
void __not_in_flash_func(ADCint)()
|
|
{
|
|
// Clear the interrupt request for DMA control channel
|
|
dma_hw->ints1 = (1u << ADC_dma_chan);
|
|
if(adcint==adcint2)adcint=adcint1;
|
|
else adcint=adcint2;
|
|
ADCDualBuffering=true;
|
|
}
|
|
/* @endcond */
|
|
|
|
void cmd_adc(void){
|
|
unsigned char *tp;
|
|
tp = checkstring(cmdline, (unsigned char *)"OPEN");
|
|
if(tp) {
|
|
getargs(&tp,5,(unsigned char *)",");
|
|
if(ADCopen)error("Already open");
|
|
if(!(argc==3 || argc==5))error("Syntax");
|
|
#ifndef PICOMITEWEB
|
|
int nbr=getint(argv[2],1,4); //number of ADC channels
|
|
#else
|
|
int nbr=getint(argv[2],1,3); //number of ADC channels
|
|
#endif
|
|
frequency=(float)getnumber(argv[0])*nbr;
|
|
if(frequency<ADC_CLK_SPEED/65536.0/96.0 || frequency> ADC_CLK_SPEED/96.0)error("Invalid frequency");
|
|
#ifdef rp2350
|
|
#ifdef PICOMITEWEB
|
|
if(!(ExtCurrentConfig[31] == EXT_ANA_IN || ExtCurrentConfig[31] == EXT_NOT_CONFIG)) error("Pin GP26 is not off or an ADC input");
|
|
if(ExtCurrentConfig[31] == EXT_NOT_CONFIG)ExtCfg(31, EXT_ANA_IN, 0);
|
|
ExtCfg(31, EXT_COM_RESERVED, 0);
|
|
if(nbr>=2){
|
|
if(!(ExtCurrentConfig[32] == EXT_ANA_IN || ExtCurrentConfig[32] == EXT_NOT_CONFIG)) error("Pin GP27 is not off or an ADC input");
|
|
if(ExtCurrentConfig[32] == EXT_NOT_CONFIG)ExtCfg(32, EXT_ANA_IN, 0);
|
|
ExtCfg(32, EXT_COM_RESERVED, 0);
|
|
}
|
|
if(nbr>=3){
|
|
if(!(ExtCurrentConfig[34] == EXT_ANA_IN || ExtCurrentConfig[34] == EXT_NOT_CONFIG)) error("Pin GP28 is not off or an ADC input");
|
|
if(ExtCurrentConfig[34] == EXT_NOT_CONFIG)ExtCfg(34, EXT_ANA_IN, 0);
|
|
ExtCfg(34, EXT_COM_RESERVED, 0);
|
|
}
|
|
#else
|
|
if(rp2350a){
|
|
if(!(ExtCurrentConfig[31] == EXT_ANA_IN || ExtCurrentConfig[31] == EXT_NOT_CONFIG)) error("Pin GP26 is not off or an ADC input");
|
|
if(ExtCurrentConfig[31] == EXT_NOT_CONFIG)ExtCfg(31, EXT_ANA_IN, 0);
|
|
ExtCfg(31, EXT_COM_RESERVED, 0);
|
|
if(nbr>=2){
|
|
if(!(ExtCurrentConfig[32] == EXT_ANA_IN || ExtCurrentConfig[32] == EXT_NOT_CONFIG)) error("Pin GP27 is not off or an ADC input");
|
|
if(ExtCurrentConfig[32] == EXT_NOT_CONFIG)ExtCfg(32, EXT_ANA_IN, 0);
|
|
ExtCfg(32, EXT_COM_RESERVED, 0);
|
|
}
|
|
if(nbr>=3){
|
|
if(!(ExtCurrentConfig[34] == EXT_ANA_IN || ExtCurrentConfig[34] == EXT_NOT_CONFIG)) error("Pin GP28 is not off or an ADC input");
|
|
if(ExtCurrentConfig[34] == EXT_NOT_CONFIG)ExtCfg(34, EXT_ANA_IN, 0);
|
|
ExtCfg(34, EXT_COM_RESERVED, 0);
|
|
}
|
|
if(nbr>=4){
|
|
if(!(ExtCurrentConfig[44] == EXT_ANA_IN || ExtCurrentConfig[44] == EXT_NOT_CONFIG)) error("Pin GP29 is not off or an ADC input");
|
|
if(ExtCurrentConfig[44] == EXT_NOT_CONFIG)ExtCfg(44, EXT_ANA_IN, 0);
|
|
ExtCfg(44, EXT_COM_RESERVED, 0);
|
|
}
|
|
} else {
|
|
if(!(ExtCurrentConfig[55] == EXT_ANA_IN || ExtCurrentConfig[55] == EXT_NOT_CONFIG)) error("Pin GP40 is not off or an ADC input");
|
|
if(ExtCurrentConfig[55] == EXT_NOT_CONFIG)ExtCfg(55, EXT_ANA_IN, 0);
|
|
ExtCfg(55, EXT_COM_RESERVED, 0);
|
|
if(nbr>=2){
|
|
if(!(ExtCurrentConfig[56] == EXT_ANA_IN || ExtCurrentConfig[56] == EXT_NOT_CONFIG)) error("Pin GP41 is not off or an ADC input");
|
|
if(ExtCurrentConfig[56] == EXT_NOT_CONFIG)ExtCfg(56, EXT_ANA_IN, 0);
|
|
ExtCfg(56, EXT_COM_RESERVED, 0);
|
|
}
|
|
if(nbr>=3){
|
|
if(!(ExtCurrentConfig[57] == EXT_ANA_IN || ExtCurrentConfig[57] == EXT_NOT_CONFIG)) error("Pin GP42 is not off or an ADC input");
|
|
if(ExtCurrentConfig[57] == EXT_NOT_CONFIG)ExtCfg(57, EXT_ANA_IN, 0);
|
|
ExtCfg(57, EXT_COM_RESERVED, 0);
|
|
}
|
|
if(nbr>=4){
|
|
if(!(ExtCurrentConfig[58] == EXT_ANA_IN || ExtCurrentConfig[58] == EXT_NOT_CONFIG)) error("Pin GP43 is not off or an ADC input");
|
|
if(ExtCurrentConfig[58] == EXT_NOT_CONFIG)ExtCfg(58, EXT_ANA_IN, 0);
|
|
ExtCfg(58, EXT_COM_RESERVED, 0);
|
|
}
|
|
}
|
|
#endif
|
|
#else
|
|
if(!(ExtCurrentConfig[31] == EXT_ANA_IN || ExtCurrentConfig[31] == EXT_NOT_CONFIG)) error("Pin GP26 is not off or an ADC input");
|
|
if(ExtCurrentConfig[31] == EXT_NOT_CONFIG)ExtCfg(31, EXT_ANA_IN, 0);
|
|
ExtCfg(31, EXT_COM_RESERVED, 0);
|
|
if(nbr>=2){
|
|
if(!(ExtCurrentConfig[32] == EXT_ANA_IN || ExtCurrentConfig[32] == EXT_NOT_CONFIG)) error("Pin GP27 is not off or an ADC input");
|
|
if(ExtCurrentConfig[32] == EXT_NOT_CONFIG)ExtCfg(32, EXT_ANA_IN, 0);
|
|
ExtCfg(32, EXT_COM_RESERVED, 0);
|
|
}
|
|
if(nbr>=3){
|
|
if(!(ExtCurrentConfig[34] == EXT_ANA_IN || ExtCurrentConfig[34] == EXT_NOT_CONFIG)) error("Pin GP28 is not off or an ADC input");
|
|
if(ExtCurrentConfig[34] == EXT_NOT_CONFIG)ExtCfg(34, EXT_ANA_IN, 0);
|
|
ExtCfg(34, EXT_COM_RESERVED, 0);
|
|
}
|
|
#ifndef PICOMITEWEB
|
|
if(nbr>=4){
|
|
if(!(ExtCurrentConfig[44] == EXT_ANA_IN || ExtCurrentConfig[44] == EXT_NOT_CONFIG)) error("Pin GP29 is not off or an ADC input");
|
|
if(ExtCurrentConfig[44] == EXT_NOT_CONFIG)ExtCfg(44, EXT_ANA_IN, 0);
|
|
ExtCfg(44, EXT_COM_RESERVED, 0);
|
|
}
|
|
#endif
|
|
#endif
|
|
if(argc==5){
|
|
InterruptUsed = true;
|
|
ADCInterrupt = (char *)GetIntAddress(argv[4]); // get the interrupt location
|
|
} else ADCInterrupt = NULL;
|
|
ADCopen=nbr;
|
|
return;
|
|
}
|
|
tp = checkstring(cmdline, (unsigned char *)"RUN");
|
|
if(tp){
|
|
getargs(&tp, 3, (unsigned char *)",");
|
|
if(!ADCopen)error("ADC not open");
|
|
if(!(argc == 3))error("Argument count");
|
|
ADCmax=0;
|
|
ADCpos=0;
|
|
adcint1=adcint2=NULL;
|
|
int64_t *adcval=NULL;
|
|
#ifdef rp2350
|
|
int dims[MAXDIM]={0};
|
|
#else
|
|
short dims[MAXDIM]={0};
|
|
#endif
|
|
int card1=parseintegerarray(argv[0], &adcval, 1, 1, dims, true);
|
|
adcint1=(uint8_t *)adcval;
|
|
adcval=NULL;
|
|
ADCmax=parseintegerarray(argv[2], &adcval, 2, 1, dims, true);
|
|
adcint2=(uint8_t *)adcval;
|
|
if(card1!=ADCmax)error("Array size mismatch %,%",card1, ADCmax);
|
|
ADCmax *=8;
|
|
dma_channel_cleanup(ADC_dma_chan);
|
|
dma_channel_cleanup(ADC_dma_chan2);
|
|
adc_init();
|
|
adc_set_round_robin(ADCopen==1 ? 1 : ADCopen==2 ? 3 : ADCopen==3 ? 7 : 15);
|
|
adc_fifo_setup(
|
|
true, // Write each completed conversion to the sample FIFO
|
|
true, // Enable DMA data request (DREQ)
|
|
1, // DREQ (and IRQ) asserted when at least 1 sample present
|
|
false, // We won't see the ERR bit because of 8 bit reads; disable.
|
|
true // Shift each sample to 8 bits when pushing to FIFO
|
|
);
|
|
adcint=adcint1;
|
|
SetADCFreq(frequency);
|
|
// Set up the DMA to start transferring data as soon as it appears in FIFO
|
|
dma_channel_config cfg = dma_channel_get_default_config(ADC_dma_chan);
|
|
|
|
// Reading from constant address, writing to incrementing byte addresses
|
|
channel_config_set_transfer_data_size(&cfg, DMA_SIZE_8);
|
|
channel_config_set_read_increment(&cfg, false);
|
|
channel_config_set_write_increment(&cfg, true);
|
|
channel_config_set_irq_quiet(&cfg, false);
|
|
channel_config_set_dreq(&cfg, DREQ_ADC);
|
|
channel_config_set_chain_to(&cfg, ADC_dma_chan2);
|
|
dma_channel_configure(ADC_dma_chan, &cfg,
|
|
adcint, // dst
|
|
&adc_hw->fifo, // src
|
|
ADCmax, // transfer count
|
|
false // start immediately
|
|
);
|
|
dma_channel_config c2 = dma_channel_get_default_config(ADC_dma_chan2); //Get configurations for control channel
|
|
channel_config_set_transfer_data_size(&c2, DMA_SIZE_32); //Set control channel data transfer size to 32 bits
|
|
channel_config_set_read_increment(&c2, false); //Set control channel read increment to false
|
|
channel_config_set_write_increment(&c2, false); //Set control channel write increment to false
|
|
channel_config_set_dreq(&c2, 0x3F);
|
|
// channel_config_set_chain_to(&c2, dma_tx_chan);
|
|
dma_channel_configure(ADC_dma_chan2,
|
|
&c2,
|
|
&dma_hw->ch[ADC_dma_chan].al2_write_addr_trig,
|
|
&adcint,
|
|
1,
|
|
false); //Configure control channel
|
|
dma_channel_set_irq1_enabled(ADC_dma_chan, true);
|
|
|
|
// set DMA IRQ handler
|
|
irq_set_exclusive_handler(DMA_IRQ_1, ADCint);
|
|
// set highest IRQ priority
|
|
irq_set_enabled(DMA_IRQ_1, true);
|
|
dma_start_channel_mask(1u << ADC_dma_chan2);
|
|
adc_run(true);
|
|
adcint=adcint2;
|
|
ADCDualBuffering=false;
|
|
return;
|
|
}
|
|
|
|
tp = checkstring(cmdline, (unsigned char *)"FREQUENCY");
|
|
if(tp) {
|
|
getargs(&tp,1,(unsigned char *)",");
|
|
if(!ADCopen)error("Not open");
|
|
float localfrequency=(float)getnumber(argv[0])*ADCopen;
|
|
if(localfrequency<ADC_CLK_SPEED/65536.0/96.0 || localfrequency> ADC_CLK_SPEED/96.0)error("Invalid frequency");
|
|
frequency=localfrequency;
|
|
return;
|
|
}
|
|
tp = checkstring(cmdline, (unsigned char *)"START");
|
|
if(tp) {
|
|
getargs(&tp, 23, (unsigned char *)",");
|
|
if(!ADCopen)error("ADC not open");
|
|
if(!(argc >= 1))error("Argument count");
|
|
a1float=NULL; a2float=NULL; a3float=NULL; a4float=NULL;
|
|
ADCmax=0;
|
|
ADCpos=0;
|
|
int card;
|
|
MMFLOAT top;
|
|
for(int i=0;i<4;i++){
|
|
ADCscale[i]=VCC/4095.0;
|
|
ADCbottom[i]=0;
|
|
}
|
|
ADCmax=parsefloatrarray(argv[0], (MMFLOAT **)&a1float, 1, 1, NULL, true);
|
|
if(argc>=3 && *argv[2]){
|
|
if(ADCopen<2)error("Second channel not open");
|
|
card=parsefloatrarray(argv[2], (MMFLOAT **)&a2float, 2, 1, NULL, true);
|
|
if(card!=ADCmax)error("Array size mismatch");
|
|
}
|
|
if(argc>=5 && *argv[4]){
|
|
if(ADCopen<3)error("Third channel not open");
|
|
card=parsefloatrarray(argv[4], (MMFLOAT **)&a3float, 3, 1, NULL, true);
|
|
if(card!=ADCmax)error("Array size mismatch");
|
|
}
|
|
if(argc>=7 && *argv[6]){
|
|
if(ADCopen<4)error("Fourth channel not open");
|
|
card=parsefloatrarray(argv[6], (MMFLOAT **)&a4float, 4, 1, NULL, true);
|
|
if(card!=ADCmax)error("Array size mismatch");
|
|
}
|
|
if(argc>=11){
|
|
ADCbottom[0]=getnumber(argv[8]);
|
|
top=getnumber(argv[10]);
|
|
ADCscale[0]=(top-ADCbottom[0])/4095.0;
|
|
}
|
|
if(argc>=15){
|
|
ADCbottom[1]=getnumber(argv[12]);
|
|
top=getnumber(argv[14]);
|
|
ADCscale[1]=(top-ADCbottom[1])/4095.0;
|
|
}
|
|
if(argc>=19){
|
|
ADCbottom[2]=getnumber(argv[16]);
|
|
top=getnumber(argv[18]);
|
|
ADCscale[2]=(top-ADCbottom[2])/4095.0;
|
|
}
|
|
if(argc>=23){
|
|
ADCbottom[3]=getnumber(argv[20]);
|
|
top=getnumber(argv[22]);
|
|
ADCscale[3]=(top-ADCbottom[3])/4095.0;
|
|
}
|
|
ADCmax++;
|
|
ADCbuffer=GetMemory(ADCmax*ADCopen*2);
|
|
adc_init();
|
|
adc_set_round_robin(ADCopen==1 ? 1 : ADCopen==2 ? 3 : ADCopen==3 ? 7 : 15);
|
|
adc_fifo_setup(
|
|
true, // Write each completed conversion to the sample FIFO
|
|
true, // Enable DMA data request (DREQ)
|
|
1, // DREQ (and IRQ) asserted when at least 1 sample present
|
|
false, // We won't see the ERR bit because of 8 bit reads; disable.
|
|
false // Shift each sample to 8 bits when pushing to FIFO
|
|
);
|
|
SetADCFreq(frequency);
|
|
// Set up the DMA to start transferring data as soon as it appears in FIFO
|
|
dma_channel_config cfg = dma_channel_get_default_config(ADC_dma_chan);
|
|
|
|
// Reading from constant address, writing to incrementing byte addresses
|
|
channel_config_set_transfer_data_size(&cfg, DMA_SIZE_16);
|
|
channel_config_set_read_increment(&cfg, false);
|
|
channel_config_set_write_increment(&cfg, true);
|
|
channel_config_set_irq_quiet(&cfg, true);
|
|
|
|
// Pace transfers based on availability of ADC samples
|
|
channel_config_set_dreq(&cfg, DREQ_ADC);
|
|
|
|
dma_channel_configure(ADC_dma_chan, &cfg,
|
|
(uint8_t *)ADCbuffer, // dst
|
|
&adc_hw->fifo, // src
|
|
ADCmax*ADCopen, // transfer count
|
|
true // start immediately
|
|
);
|
|
adc_run(true);
|
|
|
|
// Once DMA finishes, stop any new conversions from starting, and clean up
|
|
// the FIFO in case the ADC was still mid-conversion.
|
|
if(!ADCInterrupt){
|
|
while(dma_channel_is_busy(ADC_dma_chan))tight_loop_contents();
|
|
__compiler_memory_barrier();
|
|
adc_run(false);
|
|
adc_fifo_drain();
|
|
int k=0;
|
|
for(int i=0;i<ADCmax;i++){
|
|
for(int j=0;j<ADCopen;j++){
|
|
if(j==0)*a1float++ = (MMFLOAT)ADCbuffer[k++]*ADCscale[0]+ADCbottom[0];
|
|
if(j==1)*a2float++ = (MMFLOAT)ADCbuffer[k++]*ADCscale[1]+ADCbottom[1];
|
|
if(j==2)*a3float++ = (MMFLOAT)ADCbuffer[k++]*ADCscale[2]+ADCbottom[2];
|
|
if(j==3)*a4float++ = (MMFLOAT)ADCbuffer[k++]*ADCscale[3]+ADCbottom[3];
|
|
}
|
|
}
|
|
FreeMemory((void *)ADCbuffer);
|
|
adc_init();
|
|
last_adc=99;
|
|
} else dmarunning=true;
|
|
return;
|
|
}
|
|
tp = checkstring(cmdline, (unsigned char *)"CLOSE");
|
|
if(tp) {
|
|
if(!ADCopen)error("Not open");
|
|
irq_set_enabled(DMA_IRQ_1, false);
|
|
dma_hw->abort = ((1u << ADC_dma_chan2) | (1u << ADC_dma_chan));
|
|
dma_channel_abort(ADC_dma_chan);
|
|
dma_channel_abort(ADC_dma_chan2);
|
|
adc_set_round_robin(0);
|
|
SetADCFreq(500000);
|
|
#ifdef rp2350
|
|
if(rp2350a){
|
|
ExtCfg(31, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=2)ExtCfg(32, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=3)ExtCfg(34, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=4)ExtCfg(44, EXT_NOT_CONFIG, 0);
|
|
} else {
|
|
ExtCfg(55, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=2)ExtCfg(56, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=3)ExtCfg(57, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=4)ExtCfg(58, EXT_NOT_CONFIG, 0);
|
|
}
|
|
#else
|
|
ExtCfg(31, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=2)ExtCfg(32, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=3)ExtCfg(34, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=4)ExtCfg(44, EXT_NOT_CONFIG, 0);
|
|
#endif
|
|
ADCopen=0;
|
|
adcint=adcint1=adcint2=NULL;
|
|
ADCDualBuffering=false;
|
|
dmarunning=false;
|
|
last_adc=99;
|
|
adc_init();
|
|
return;
|
|
}
|
|
error("Syntax");
|
|
}
|
|
void SetADCFreq(float frequency){
|
|
//Our ADC clock is running at ADC_CLK_SPEED (in Hz) so we need to stretch the time to produce the required frequency
|
|
//The time delta for our frequency is 1/frequency*96 - 1/(ADC_CLK_SPEED) seconds
|
|
//This must be added to clk_div as a number of CPU clock ticks i.e. delta/(1/ADC_CLK_SPEED)
|
|
//Plus we need to add 95 to cater for the actual time taken for the conversion
|
|
double delta = 1.0/(frequency*96.0) - 1.0/((double)ADC_CLK_SPEED);
|
|
float div=delta/(1.0/((double)ADC_CLK_SPEED))*96.0 +95.0;
|
|
if(div<=96.0)div=0;
|
|
adc_set_clkdiv(div);
|
|
}
|
|
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
void MIPS16 ClearExternalIO(void) {
|
|
int i;
|
|
CloseAudio(1);
|
|
#ifndef PICOMITEVGA
|
|
cameraclose();
|
|
#endif
|
|
InterruptUsed = false;
|
|
InterruptReturn = NULL;
|
|
irq_set_enabled(DMA_IRQ_1, false);
|
|
#ifdef rp2350
|
|
irq_set_enabled(PWM_IRQ_WRAP_1, false);
|
|
#endif
|
|
closeframebuffer('A');
|
|
if(CallBackEnabled==1) gpio_set_irq_enabled_with_callback(PinDef[IRpin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
|
else if(CallBackEnabled & 1){
|
|
gpio_set_irq_enabled(PinDef[IRpin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
|
CallBackEnabled &= (~1);
|
|
}
|
|
if(CallBackEnabled==2) gpio_set_irq_enabled_with_callback(PinDef[Option.INT1pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
|
else if(CallBackEnabled & 2){
|
|
gpio_set_irq_enabled(PinDef[Option.INT1pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
|
CallBackEnabled &= (~2);
|
|
}
|
|
if(CallBackEnabled==4) gpio_set_irq_enabled_with_callback(PinDef[Option.INT2pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
|
else if(CallBackEnabled & 4){
|
|
gpio_set_irq_enabled(PinDef[Option.INT2pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
|
CallBackEnabled &= (~4);
|
|
}
|
|
if(CallBackEnabled==8) gpio_set_irq_enabled_with_callback(PinDef[Option.INT3pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
|
else if(CallBackEnabled & 8){
|
|
gpio_set_irq_enabled(PinDef[Option.INT3pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
|
CallBackEnabled &= (~8);
|
|
}
|
|
if(CallBackEnabled==16) gpio_set_irq_enabled_with_callback(PinDef[Option.INT4pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
|
else if(CallBackEnabled & 16){
|
|
gpio_set_irq_enabled(PinDef[Option.INT4pin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false);
|
|
CallBackEnabled &= (~16);
|
|
}
|
|
CallBackEnabled &= (~32);
|
|
for(i=0;i<MAXBLITBUF;i++){
|
|
spritebuff[i].spritebuffptr = NULL;
|
|
blitbuff[i].blitbuffptr = NULL;
|
|
}
|
|
CallBackEnabled=0;
|
|
KeypadClose();
|
|
if(*lcd_pins){
|
|
for(i = 0; i < 6; i++) {
|
|
ExtCfg(lcd_pins[i], EXT_NOT_CONFIG, 0); // all set to unconfigured
|
|
*lcd_pins = 0;
|
|
}
|
|
}
|
|
memset(lcd_pins,0,sizeof(lcd_pins));
|
|
SerialClose(1);
|
|
SerialClose(2); // same for serial ports
|
|
if(!I2C0locked)i2c_disable();
|
|
if(!I2C1locked)i2c2_disable();
|
|
sprite_transparent=0;
|
|
SPIClose();
|
|
SPI2Close();
|
|
if(IRpin!=99){
|
|
gpio_set_irq_enabled_with_callback(PinDef[IRpin].GPno, GPIO_IRQ_EDGE_RISE | GPIO_IRQ_EDGE_FALL, false, &gpio_callback);
|
|
IrInterrupt = NULL;
|
|
ExtCfg(IRpin, EXT_NOT_CONFIG, 0);
|
|
}
|
|
ResetDisplay();
|
|
IrState = IR_CLOSED;
|
|
IrInterrupt = NULL;
|
|
IrGotMsg = false;
|
|
memset(&PIDchannels,0,sizeof(s_PIDchan)*(MAXPID+1));
|
|
#ifdef rp2350
|
|
#ifdef PICOMITEWEB
|
|
for(i = 1; i < (NBRPINS) ; i++) {
|
|
if(CheckPin(i, CP_NOABORT | CP_IGNORE_INUSE | CP_IGNORE_RESERVED)) { // don't reset invalid or boot reserved pins
|
|
ExtCfg(i, EXT_NOT_CONFIG, 0); // all set to unconfigured
|
|
}
|
|
}
|
|
#else
|
|
for(i = 1; i < (rp2350a ? 44: NBRPINS) ; i++) {
|
|
if(CheckPin(i, CP_NOABORT | CP_IGNORE_INUSE | CP_IGNORE_RESERVED)) { // don't reset invalid or boot reserved pins
|
|
ExtCfg(i, EXT_NOT_CONFIG, 0); // all set to unconfigured
|
|
}
|
|
}
|
|
#endif
|
|
#else
|
|
for(i = 1; i < (NBRPINS) ; i++) {
|
|
if(CheckPin(i, CP_NOABORT | CP_IGNORE_INUSE | CP_IGNORE_RESERVED)) { // don't reset invalid or boot reserved pins
|
|
ExtCfg(i, EXT_NOT_CONFIG, 0); // all set to unconfigured
|
|
}
|
|
}
|
|
#endif
|
|
for(i = 0; i < NBRINTERRUPTS; i++) {
|
|
inttbl[i].pin = 0; // disable all interrupts
|
|
}
|
|
#ifndef PICOMITEWEB
|
|
if(!Option.AllPins){
|
|
if(CheckPin(41, CP_NOABORT | CP_IGNORE_INUSE | CP_IGNORE_RESERVED))ExtCfg(41,EXT_DIG_OUT,Option.PWM);
|
|
if(CheckPin(42, CP_NOABORT | CP_IGNORE_INUSE | CP_IGNORE_RESERVED))ExtCfg(42,EXT_DIG_IN,0);
|
|
if(CheckPin(44, CP_NOABORT | CP_IGNORE_INUSE | CP_IGNORE_RESERVED))ExtCfg(44,EXT_ANA_IN,0);
|
|
}
|
|
if(CheckPin(HEARTBEATpin, CP_NOABORT | CP_IGNORE_INUSE | CP_IGNORE_RESERVED) && !Option.NoHeartbeat){
|
|
gpio_init(PinDef[HEARTBEATpin].GPno);
|
|
gpio_set_dir(PinDef[HEARTBEATpin].GPno, GPIO_OUT);
|
|
ExtCurrentConfig[PinDef[HEARTBEATpin].pin]=EXT_HEARTBEAT;
|
|
}
|
|
#endif
|
|
FreeMemorySafe((void **)&ds18b20Timers);
|
|
KeypadInterrupt = NULL;
|
|
|
|
for(i = 0; i < NBRSETTICKS; i++) TickInt[i] = NULL;
|
|
for(i = 0; i < NBRSETTICKS; i++) TickActive[i] = 0;
|
|
for(i = 0; i < NBR_PULSE_SLOTS; i++) PulseCnt[i] = 0; // disable any pending pulse commands
|
|
PulseActive = false;
|
|
#ifdef rp2350
|
|
slice0=0;slice1=0;slice2=0;slice3=0;slice4=0;slice5=0;slice6=0;slice7=0;slice8=0;slice9=0;slice10=0;slice11=0;
|
|
for(i=0; i<=(rp2350a ? 7:11);i++)if(!(i==Option.AUDIO_SLICE || i==BacklightSlice))PWMoff(i);
|
|
#else
|
|
slice0=0;slice1=0;slice2=0;slice3=0;slice4=0;slice5=0;slice6=0;slice7=0;
|
|
for(i=0; i<=7;i++)if(!(i==Option.AUDIO_SLICE || i==BacklightSlice))PWMoff(i);
|
|
#endif
|
|
IRpin=99;
|
|
PWM0Apin=99;
|
|
PWM1Apin=99;
|
|
PWM2Apin=99;
|
|
PWM3Apin=99;
|
|
PWM4Apin=99;
|
|
PWM5Apin=99;
|
|
PWM6Apin=99;
|
|
PWM7Apin=99;
|
|
#ifdef rp2350
|
|
PWM8Apin=99;
|
|
PWM9Apin=99;
|
|
PWM10Apin=99;
|
|
PWM11Apin=99;
|
|
#endif
|
|
PWM0Bpin=99;
|
|
PWM1Bpin=99;
|
|
PWM2Bpin=99;
|
|
PWM3Bpin=99;
|
|
PWM4Bpin=99;
|
|
PWM5Bpin=99;
|
|
PWM6Bpin=99;
|
|
PWM7Bpin=99;
|
|
#ifdef rp2350
|
|
PWM8Bpin=99;
|
|
PWM9Bpin=99;
|
|
PWM10Bpin=99;
|
|
PWM11Bpin=99;
|
|
#endif
|
|
UART1RXpin=99;
|
|
UART1TXpin=99;
|
|
UART0TXpin=99;
|
|
UART0RXpin=99;
|
|
SPI0TXpin=99;
|
|
SPI0RXpin=99;
|
|
SPI0SCKpin=99;
|
|
SPI1TXpin=99;
|
|
SPI1RXpin=99;
|
|
SPI1SCKpin=99;
|
|
if(!I2C0locked){
|
|
I2C0SDApin=99;
|
|
I2C0SCLpin=99;
|
|
}
|
|
if(!I2C1locked){
|
|
I2C1SDApin=99;
|
|
I2C1SCLpin=99;
|
|
}
|
|
#ifdef rp2350
|
|
if(rp2350a){
|
|
if(ADCopen) ExtCfg(31, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=2)ExtCfg(32, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=3)ExtCfg(34, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=4)ExtCfg(44, EXT_NOT_CONFIG, 0);
|
|
} else {
|
|
if(ADCopen) ExtCfg(55, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=2)ExtCfg(56, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=3)ExtCfg(57, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=4)ExtCfg(58, EXT_NOT_CONFIG, 0);
|
|
}
|
|
#else
|
|
if(ADCopen) ExtCfg(31, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=2)ExtCfg(32, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=3)ExtCfg(34, EXT_NOT_CONFIG, 0);
|
|
if(ADCopen>=4)ExtCfg(44, EXT_NOT_CONFIG, 0);
|
|
#endif
|
|
ADCopen=0;
|
|
adc_set_round_robin(0);
|
|
SetADCFreq(500000);
|
|
KeyInterrupt=NULL;
|
|
OnKeyGOSUB=NULL;
|
|
#ifndef USBKEYBOARD
|
|
OnPS2GOSUB=NULL;
|
|
PS2code=0;
|
|
PS2int=false;
|
|
if(!Option.MOUSE_CLOCK)mouse0close();
|
|
#endif
|
|
for (int i=0; i<6;i++)nunInterruptc[i]=NULL;
|
|
if((classic1 || nunchuck1) && (classicread || nunchuckread))WiiReceive(6, (char *)nunbuff);
|
|
classic1=0;
|
|
nunchuck1=0;
|
|
classicread=false;
|
|
nunchuckread=false;
|
|
#ifdef PICOMITEWEB
|
|
MQTTInterrupt=NULL;
|
|
MQTTComplete=0;
|
|
closeMQTT();
|
|
#endif
|
|
#ifndef PICOMITEWEB
|
|
#ifdef PICOMITEVGA
|
|
CollisionFound = false;
|
|
COLLISIONInterrupt=NULL;
|
|
#endif
|
|
#endif
|
|
#ifdef GUICONTROLS
|
|
gui_int_down = false;
|
|
gui_int_up = false;
|
|
GuiIntDownVector=NULL;
|
|
GuiIntUpVector=NULL;
|
|
#endif
|
|
dmarunning=false;
|
|
ADCDualBuffering=false;
|
|
ADCInterrupt=NULL;
|
|
CSubInterrupt=NULL;
|
|
CSubComplete=0;
|
|
keyselect=0;
|
|
g_myrand=NULL;
|
|
CMM1=0;
|
|
dirOK=2;
|
|
nextline[0]=0;nextline[1]=0;nextline[2]=0;nextline[3]=99;
|
|
memset(pioTXlast,0,sizeof(pioTXlast));
|
|
memset(pioRXinterrupts,0,sizeof(pioRXinterrupts));
|
|
memset(pioTXinterrupts,0,sizeof(pioTXinterrupts));
|
|
piointerrupt=0;
|
|
DMAinterruptRX=NULL;
|
|
DMAinterruptTX=NULL;
|
|
WAVInterrupt=NULL;
|
|
dma_hw->abort = ((1u << dma_rx_chan2) | (1u << dma_rx_chan));
|
|
if(dma_channel_is_busy(dma_rx_chan))dma_channel_abort(dma_rx_chan);
|
|
if(dma_channel_is_busy(dma_rx_chan2))dma_channel_abort(dma_rx_chan2);
|
|
// dma_channel_cleanup(dma_rx_chan);
|
|
// dma_channel_cleanup(dma_rx_chan2);
|
|
dma_hw->abort = ((1u << dma_tx_chan2) | (1u << dma_tx_chan));
|
|
if(dma_channel_is_busy(dma_tx_chan))dma_channel_abort(dma_tx_chan);
|
|
if(dma_channel_is_busy(dma_tx_chan2))dma_channel_abort(dma_tx_chan2);
|
|
// dma_channel_cleanup(dma_tx_chan);
|
|
// dma_channel_cleanup(dma_tx_chan2);
|
|
dma_hw->abort = ((1u << ADC_dma_chan2) | (1u << ADC_dma_chan));
|
|
if(dma_channel_is_busy(ADC_dma_chan))dma_channel_abort(ADC_dma_chan);
|
|
if(dma_channel_is_busy(ADC_dma_chan2))dma_channel_abort(ADC_dma_chan2);
|
|
// dma_channel_cleanup(ADC_dma_chan);
|
|
// dma_channel_cleanup(ADC_dma_chan2);
|
|
adcint=adcint1=adcint2=NULL;
|
|
}
|
|
|
|
|
|
|
|
void __not_in_flash_func(TM_EXTI_Handler_1)(void) {
|
|
if(ExtCurrentConfig[Option.INT1pin] == EXT_PER_IN) {
|
|
if(--INT1Timer <= 0) {
|
|
INT1Value = INT1Count;
|
|
INT1Timer = INT1InitTimer;
|
|
INT1Count = 0;
|
|
}
|
|
}
|
|
else {
|
|
if(CFuncInt1)
|
|
CallCFuncInt1(); // Hardware interrupt 2 for a CFunction (see CFunction.c)
|
|
else
|
|
INT1Count++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// perform the counting functions for INT2
|
|
void __not_in_flash_func(TM_EXTI_Handler_2)(void) {
|
|
if(ExtCurrentConfig[Option.INT2pin] == EXT_PER_IN) {
|
|
if(--INT2Timer <= 0) {
|
|
INT2Value = INT2Count;
|
|
INT2Timer = INT2InitTimer;
|
|
INT2Count = 0;
|
|
}
|
|
}
|
|
else {
|
|
if(CFuncInt2)
|
|
CallCFuncInt2(); // Hardware interrupt 2 for a CFunction (see CFunction.c)
|
|
else
|
|
INT2Count++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// perform the counting functions for INT3
|
|
void __not_in_flash_func(TM_EXTI_Handler_3)(void) {
|
|
if(ExtCurrentConfig[Option.INT3pin] == EXT_PER_IN) {
|
|
if(--INT3Timer <= 0) {
|
|
INT3Value = INT3Count;
|
|
INT3Timer = INT3InitTimer;
|
|
INT3Count = 0;
|
|
}
|
|
}
|
|
else {
|
|
if(CFuncInt3)
|
|
CallCFuncInt3(); // Hardware interrupt 2 for a CFunction (see CFunction.c)
|
|
else
|
|
INT3Count++;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
// perform the counting functions for INT4
|
|
void __not_in_flash_func(TM_EXTI_Handler_4)(void) {
|
|
if(ExtCurrentConfig[Option.INT4pin] == EXT_PER_IN) {
|
|
if(--INT4Timer <= 0) {
|
|
INT4Value = INT4Count;
|
|
INT4Timer = INT4InitTimer;
|
|
INT4Count = 0;
|
|
}
|
|
}
|
|
else {
|
|
if(CFuncInt4)
|
|
CallCFuncInt4(); // Hardware interrupt 2 for a CFunction (see CFunction.c)
|
|
else
|
|
INT4Count++;
|
|
}
|
|
|
|
}
|
|
void MIPS16 __not_in_flash_func(IRHandler)(void) {
|
|
int ElapsedMicroSec;
|
|
static unsigned int LastIrBits;
|
|
ElapsedMicroSec = readIRclock();
|
|
switch(IrState) {
|
|
case IR_WAIT_START:
|
|
writeIRclock(0); // reset the timer
|
|
IrState = IR_WAIT_START_END; // wait for the end of the start bit
|
|
break;
|
|
case IR_WAIT_START_END:
|
|
if(ElapsedMicroSec > 2000 && ElapsedMicroSec < 2800)
|
|
IrState = SONY_WAIT_BIT_START; // probably a Sony remote, now wait for the first data bit
|
|
else if(ElapsedMicroSec > 8000 && ElapsedMicroSec < 10000)
|
|
IrState = NEC_WAIT_FIRST_BIT_START; // probably an NEC remote, now wait for the first data bit
|
|
else {
|
|
IrReset(); // the start bit was not valid
|
|
break;
|
|
}
|
|
IrCount = 0; // count the bits in the message
|
|
IrBits = 0; // reset the bit accumulator
|
|
writeIRclock(0); // reset the timer
|
|
break;
|
|
case SONY_WAIT_BIT_START:
|
|
if(ElapsedMicroSec < 300 || ElapsedMicroSec > 900) { IrReset(); break; }
|
|
writeIRclock(0); // reset the timer
|
|
IrState = SONY_WAIT_BIT_END; // wait for the end of this data bit
|
|
break;
|
|
case SONY_WAIT_BIT_END:
|
|
if(ElapsedMicroSec < 300 || ElapsedMicroSec > 1500 || IrCount > 20) { IrReset(); break; }
|
|
IrBits |= (ElapsedMicroSec > 900) << IrCount; // get the data bit
|
|
IrCount++; // and increment our count
|
|
writeIRclock(0); // reset the timer
|
|
IrState = SONY_WAIT_BIT_START; // go back and wait for the next data bit
|
|
break;
|
|
case NEC_WAIT_FIRST_BIT_START:
|
|
if(ElapsedMicroSec > 2000 && ElapsedMicroSec < 2500) {
|
|
IrBits = LastIrBits; // key is held down so just repeat the last code
|
|
IrCount = 32; // and signal that we are finished
|
|
IrState = NEC_WAIT_BIT_END;
|
|
break;
|
|
}
|
|
else if(ElapsedMicroSec > 4000 && ElapsedMicroSec < 5000)
|
|
IrState = NEC_WAIT_BIT_END; // wait for the end of this data bit
|
|
else {
|
|
IrReset(); // the start bit was not valid
|
|
break;
|
|
}
|
|
writeIRclock(0); // reset the timer
|
|
break;
|
|
case NEC_WAIT_BIT_START:
|
|
if(ElapsedMicroSec < 400 || ElapsedMicroSec > 1800) { IrReset(); break; }
|
|
IrBits |= (ElapsedMicroSec > 840) << (31 - IrCount);// get the data bit
|
|
LastIrBits = IrBits;
|
|
IrCount++; // and increment our count
|
|
writeIRclock(0); // reset the timer
|
|
IrState = NEC_WAIT_BIT_END; // wait for the end of this data bit
|
|
break;
|
|
case NEC_WAIT_BIT_END:
|
|
if(ElapsedMicroSec < 400 || ElapsedMicroSec > 700) { IrReset(); break; }
|
|
if(IrCount == 32) break;
|
|
writeIRclock(0); // reset the timer
|
|
IrState = NEC_WAIT_BIT_START; // go back and wait for the next data bit
|
|
break;
|
|
}
|
|
}
|
|
void __not_in_flash_func(gpio_callback)(uint gpio, uint32_t events) {
|
|
#ifndef USBKEYBOARD
|
|
static uint64_t data;
|
|
data=gpio_get_all64();
|
|
if(Option.KEYBOARD_CLOCK) if( !(Option.KeyboardConfig == NO_KEYBOARD || Option.KeyboardConfig == CONFIG_I2C ) && gpio==PinDef[Option.KEYBOARD_CLOCK].GPno) CNInterrupt(data);
|
|
if(MOUSE_CLOCK && gpio==PinDef[MOUSE_CLOCK].GPno)MNInterrupt(data);
|
|
#endif
|
|
if(gpio==PinDef[IRpin].GPno)IRHandler();
|
|
if(gpio==PinDef[Option.INT1pin].GPno)TM_EXTI_Handler_1();
|
|
if(gpio==PinDef[Option.INT2pin].GPno)TM_EXTI_Handler_2();
|
|
if(gpio==PinDef[Option.INT3pin].GPno)TM_EXTI_Handler_3();
|
|
if(gpio==PinDef[Option.INT4pin].GPno)TM_EXTI_Handler_4();
|
|
}
|
|
/* @endcond */
|
|
|