mirror of
https://github.com/clockworkpi/PicoCalc.git
synced 2025-12-12 10:18:54 +01:00
2464 lines
89 KiB
C
2464 lines
89 KiB
C
/***********************************************************************************************************************
|
|
PicoMite MMBasic
|
|
|
|
I2C.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.
|
|
|
|
************************************************************************************************************************/
|
|
/**
|
|
* @file I2C.c
|
|
* @author Geoff Graham, Peter Mather
|
|
* @brief Source for I2C MMBasic commands
|
|
*/
|
|
/**
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
#include "MMBasic_Includes.h"
|
|
|
|
#include "Hardware_Includes.h"
|
|
|
|
#include "hardware/i2c.h"
|
|
|
|
#include "hardware/irq.h"
|
|
|
|
#define nunaddr 0xA4 / 2;
|
|
#define PinRead(a) gpio_get(PinDef[a].GPno)
|
|
extern void DrawBufferMEM(int x1, int y1, int x2, int y2, unsigned char * p);
|
|
extern void ReadBufferMEM(int x1, int y1, int x2, int y2, unsigned char * buff);
|
|
// Declare functions
|
|
void i2cEnable(unsigned char * p);
|
|
void i2cDisable(unsigned char * p);
|
|
void i2cSend(unsigned char * p);
|
|
void i2cSendSlave(unsigned char * p, int channel);
|
|
void i2cReceive(unsigned char * p);
|
|
void i2c_disable(void);
|
|
void i2c_enable(int bps);
|
|
void i2c_masterCommand(int timer, unsigned char * buff);
|
|
void i2cCheck(unsigned char * p);
|
|
void i2c2Enable(unsigned char * p);
|
|
void i2c2Disable(unsigned char * p);
|
|
void i2c2Send(unsigned char * p);
|
|
void i2c2Receive(unsigned char * p);
|
|
void i2c2_disable(void);
|
|
void i2c2_enable(int bps);
|
|
void i2c2_masterCommand(int timer, unsigned char * buff);
|
|
void i2c2Check(unsigned char * p);
|
|
static MMFLOAT * I2C_Rcvbuf_Float; // pointer to the master receive buffer for a MMFLOAT
|
|
static long long int * I2C_Rcvbuf_Int; // pointer to the master receive buffer for an integer
|
|
static char * I2C_Rcvbuf_String; // pointer to the master receive buffer for a string
|
|
static unsigned int I2C_Addr; // I2C device address
|
|
static volatile unsigned int I2C_Sendlen; // length of the master send buffer
|
|
static volatile unsigned int I2C_Rcvlen; // length of the master receive buffer
|
|
static unsigned char I2C_Send_Buffer[256]; // I2C send buffer
|
|
bool I2C_enabled = false; // I2C enable marker
|
|
unsigned int I2C_Timeout; // master timeout value
|
|
volatile unsigned int I2C_Status; // status flags
|
|
int mmI2Cvalue;
|
|
// value of MM.I2C
|
|
static MMFLOAT * I2C2_Rcvbuf_Float; // pointer to the master receive buffer for a MMFLOAT
|
|
static long long int * I2C2_Rcvbuf_Int; // pointer to the master receive buffer for an integer
|
|
static char * I2C2_Rcvbuf_String; // pointer to the master receive buffer for a string
|
|
static unsigned int I2C2_Addr; // I2C device address
|
|
static volatile unsigned int I2C2_Sendlen; // length of the master send buffer
|
|
static volatile unsigned int I2C2_Rcvlen; // length of the master receive buffer
|
|
//static unsigned char I2C_Send_Buffer[256]; // I2C send buffer
|
|
bool I2C2_enabled = false; // I2C enable marker
|
|
unsigned int I2C2_Timeout; // master timeout value
|
|
volatile unsigned int I2C2_Status; // status flags
|
|
//static char I2C_Rcv_Buffer[256]; // I2C receive buffer
|
|
static unsigned int I2C_Slave_Addr; // slave address
|
|
char * I2C_Slave_Send_IntLine; // pointer to the slave send interrupt line number
|
|
char * I2C_Slave_Receive_IntLine; // pointer to the slave receive interrupt line number
|
|
//static char I2C2_Rcv_Buffer[256]; // I2C receive buffer
|
|
char * I2C2_Slave_Send_IntLine; // pointer to the slave send interrupt line number
|
|
char * I2C2_Slave_Receive_IntLine; // pointer to the slave receive interrupt line number
|
|
static unsigned int I2C2_Slave_Addr; // slave address
|
|
bool noRTC = false, noI2C = false;
|
|
extern void SaveToBuffer(void);
|
|
extern void CompareToBuffer(void);
|
|
extern void DrawPixelMEM(int x1, int y1, int c);
|
|
extern void DrawRectangleMEM(int x1, int y1, int x2, int y2, int c);
|
|
extern void DrawBitmapMEM(int x1, int y1, int width, int height, int scale, int fc, int bc, unsigned char * bitmap);
|
|
void i2cSlave(unsigned char * p);
|
|
void i2c2Slave(unsigned char * p);
|
|
void i2cReceiveSlave(unsigned char * p, int channel);
|
|
int CameraSlice = -1;
|
|
int CameraChannel = -1;
|
|
extern void PWMoff(int slice);
|
|
const unsigned char nuninit[2] = {
|
|
0xF0,
|
|
0x55
|
|
};
|
|
const unsigned char nuninit2[2] = {
|
|
0xFB,
|
|
0x0
|
|
};
|
|
const unsigned char readcontroller[1] = {
|
|
0
|
|
};
|
|
const unsigned char nunid[1] = {
|
|
0xFC
|
|
};
|
|
const unsigned char nuncalib[1] = {
|
|
0x20
|
|
};
|
|
volatile uint8_t classic1 = false, nunchuck1 = false;
|
|
uint8_t nunbuff[10];
|
|
uint32_t swap32(uint32_t in ) {
|
|
in = __builtin_bswap32(in);
|
|
return in;
|
|
}
|
|
volatile struct s_nunstruct nunstruct[6];
|
|
char * nunInterruptc[6] = {
|
|
NULL
|
|
};
|
|
bool nunfoundc[6] = {
|
|
false
|
|
};
|
|
unsigned char classicread = 0, nunchuckread = 0;
|
|
/*******************************************************************************************
|
|
I2C related commands in MMBasic
|
|
===============================
|
|
These are the functions responsible for executing the I2C related commands in MMBasic
|
|
They are supported by utility functions that are grouped at the end of this file
|
|
|
|
********************************************************************************************/
|
|
#ifdef PICOCALC
|
|
void I2C_Send_RegData(int i2caddr,int reg,char command){
|
|
int i2cret;
|
|
I2C_Send_Buffer[0]=reg;
|
|
I2C_Send_Buffer[1]=command;
|
|
I2C_Sendlen=2;
|
|
I2C_Timeout=1000;
|
|
if(I2C1locked)i2cret=i2c_write_timeout_us(i2c1, (uint8_t)i2caddr, (uint8_t *)I2C_Send_Buffer, I2C_Sendlen,false, I2C_Timeout*1000);
|
|
else i2cret=i2c_write_timeout_us(i2c0, (uint8_t)i2caddr, (uint8_t *)I2C_Send_Buffer, I2C_Sendlen,false, I2C_Timeout*1000);
|
|
mmI2Cvalue=0;
|
|
if(i2cret==PICO_ERROR_GENERIC)mmI2Cvalue=1;
|
|
if(i2cret==PICO_ERROR_TIMEOUT)mmI2Cvalue=2;
|
|
// mmI2Cvalue=HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)i2caddr, I2C_Send_Buffer, I2C_Sendlen, I2C_Timeout);
|
|
}
|
|
#endif
|
|
void I2C_Send_Command(char command) {
|
|
int i2cret;
|
|
int i2caddr = SSD1306_I2C_Addr;
|
|
I2C_Send_Buffer[0] = 0;
|
|
I2C_Send_Buffer[1] = command;
|
|
I2C_Sendlen = 2;
|
|
I2C_Timeout = 1000;
|
|
if (I2C1locked) i2cret = i2c_write_timeout_us(i2c1, (uint8_t) i2caddr, (uint8_t * ) I2C_Send_Buffer, I2C_Sendlen, false, I2C_Timeout * 1000);
|
|
else i2cret = i2c_write_timeout_us(i2c0, (uint8_t) i2caddr, (uint8_t * ) I2C_Send_Buffer, I2C_Sendlen, false, I2C_Timeout * 1000);
|
|
mmI2Cvalue = 0;
|
|
if (i2cret == PICO_ERROR_GENERIC) mmI2Cvalue = 1;
|
|
if (i2cret == PICO_ERROR_TIMEOUT) mmI2Cvalue = 2;
|
|
// mmI2Cvalue=HAL_I2C_Master_Transmit(&hi2c1, (uint16_t)i2caddr, I2C_Send_Buffer, I2C_Sendlen, I2C_Timeout);
|
|
}
|
|
void I2C_Send_Data(unsigned char * data, int n) {
|
|
int i2cret;
|
|
int i, i2caddr = SSD1306_I2C_Addr;
|
|
I2C_Sendlen = n + 1;
|
|
I2C_Send_Buffer[0] = 0x40;
|
|
I2C_Timeout = 1000;
|
|
for (i = 1; i <= n; i++) {
|
|
I2C_Send_Buffer[i] = data[i - 1];
|
|
}
|
|
if (I2C1locked) i2cret = i2c_write_timeout_us(i2c1, (uint8_t) i2caddr, (uint8_t * ) I2C_Send_Buffer, I2C_Sendlen, false, I2C_Timeout * 1000);
|
|
else i2cret = i2c_write_timeout_us(i2c0, (uint8_t) i2caddr, (uint8_t * ) I2C_Send_Buffer, I2C_Sendlen, false, I2C_Timeout * 1000);
|
|
mmI2Cvalue = 0;
|
|
if (i2cret == PICO_ERROR_GENERIC) mmI2Cvalue = 1;
|
|
if (i2cret == PICO_ERROR_TIMEOUT) mmI2Cvalue = 2;
|
|
}
|
|
#ifndef PICOMITEVGA
|
|
void ConfigDisplayI2C(unsigned char * p) {
|
|
unsigned char DISPLAY_TYPE = 0;
|
|
getargs( & p, 5, (unsigned char * )
|
|
",");
|
|
if (!(argc == 3 || argc == 5)) error("Argument count");
|
|
if (checkstring(argv[0], (unsigned char * )
|
|
"SSD1306I2C")) {
|
|
DISPLAY_TYPE = SSD1306I2C;
|
|
} else if (checkstring(argv[0], (unsigned char * )
|
|
"SSD1306I2C32")) {
|
|
DISPLAY_TYPE = SSD1306I2C32;
|
|
} else
|
|
error("Invalid display type");
|
|
|
|
if (checkstring(argv[2], (unsigned char * )
|
|
"L") || checkstring(argv[2], (unsigned char * )
|
|
"LANDSCAPE"))
|
|
Option.DISPLAY_ORIENTATION = LANDSCAPE;
|
|
else if (checkstring(argv[2], (unsigned char * )
|
|
"P") || checkstring(argv[2], (unsigned char * )
|
|
"PORTRAIT"))
|
|
Option.DISPLAY_ORIENTATION = PORTRAIT;
|
|
else if (checkstring(argv[2], (unsigned char * )
|
|
"RL") || checkstring(argv[2], (unsigned char * )
|
|
"RLANDSCAPE"))
|
|
Option.DISPLAY_ORIENTATION = RLANDSCAPE;
|
|
else if (checkstring(argv[2], (unsigned char * )
|
|
"RP") || checkstring(argv[2], (unsigned char * )
|
|
"RPORTRAIT"))
|
|
Option.DISPLAY_ORIENTATION = RPORTRAIT;
|
|
else error("Orientation");
|
|
Option.I2Coffset = 0;
|
|
if (argc == 5) Option.I2Coffset = getint(argv[4], 0, 10);
|
|
if (!(I2C0locked || I2C1locked)) error("SYSTEM I2C not configured");
|
|
Option.Refresh = 1;
|
|
Option.DISPLAY_TYPE = DISPLAY_TYPE;
|
|
}
|
|
|
|
void InitDisplayI2C(int InitOnly) {
|
|
if (Option.DISPLAY_TYPE == 0 || Option.DISPLAY_TYPE > I2C_PANEL) return;
|
|
// I2Con();
|
|
// i2c_enable(display_details[Option.DISPLAY_TYPE].speed);
|
|
DrawRectangle = DrawRectangleMEM;
|
|
DrawBitmap = DrawBitmapMEM;
|
|
DrawBuffer = DrawBufferMEM;
|
|
ReadBuffer = ReadBufferMEM;
|
|
DrawPixel = DrawPixelMEM;
|
|
DrawBLITBuffer = DrawBufferMEM;
|
|
ReadBLITBuffer = ReadBufferMEM;
|
|
DisplayHRes = display_details[Option.DISPLAY_TYPE].horizontal;
|
|
DisplayVRes = display_details[Option.DISPLAY_TYPE].vertical;
|
|
I2C_Send_Command(0xAE); //DISPLAYOFF
|
|
|
|
I2C_Send_Command(0xD5); //DISPLAYCLOCKDIV
|
|
I2C_Send_Command(0xF0); //the suggested ratio &H80
|
|
|
|
I2C_Send_Command(0xA8); //MULTIPLEX
|
|
if (Option.DISPLAY_TYPE == SSD1306I2C) I2C_Send_Command(0x3F);
|
|
else if (Option.DISPLAY_TYPE == SSD1306I2C32) I2C_Send_Command(0x1F);
|
|
|
|
I2C_Send_Command(0xD3); //DISPLAYOFFSET
|
|
I2C_Send_Command(0x0); //no offset
|
|
|
|
I2C_Send_Command(0x40); //STARTLINE
|
|
|
|
I2C_Send_Command(0x8D); //CHARGEPUMP
|
|
I2C_Send_Command(0x14);
|
|
|
|
I2C_Send_Command(0x20); //MEMORYMODE
|
|
I2C_Send_Command(0x00); //&H0 act like ks0108
|
|
|
|
I2C_Send_Command(0xA1); //SEGREMAP OR 1
|
|
I2C_Send_Command(0xC8); //COMSCANDEC
|
|
|
|
I2C_Send_Command(0xDA); //COMPINS
|
|
if (Option.DISPLAY_TYPE == SSD1306I2C) I2C_Send_Command(0x12);
|
|
else if (Option.DISPLAY_TYPE == SSD1306I2C32) I2C_Send_Command(0x02);
|
|
|
|
I2C_Send_Command(0x81); //SETCONTRAST
|
|
I2C_Send_Command(0xCF);
|
|
|
|
I2C_Send_Command(0xd9); //SETPRECHARGE
|
|
I2C_Send_Command(0x22);
|
|
|
|
I2C_Send_Command(0xDB); //VCOMDETECT
|
|
I2C_Send_Command(0x20);
|
|
|
|
I2C_Send_Command(0xA4); //DISPLAYALLON_RESUME
|
|
I2C_Send_Command(0xA6); //NORMALDISPLAY
|
|
I2C_Send_Command(0xAF); //DISPLAYON
|
|
if (Option.DISPLAY_ORIENTATION & 1) {
|
|
VRes = DisplayVRes;
|
|
HRes = DisplayHRes;
|
|
} else {
|
|
VRes = DisplayHRes;
|
|
HRes = DisplayVRes;
|
|
}
|
|
if (!InitOnly) {
|
|
ResetDisplay();
|
|
ClearScreen(0);
|
|
Display_Refresh();
|
|
}
|
|
}
|
|
#endif
|
|
/* @endcond */
|
|
|
|
void cmd_i2c(void) {
|
|
unsigned char * p; //, *pp;
|
|
if (I2C0SDApin == 99 || I2C0SCLpin == 99) error("Pin not set for I2C");
|
|
|
|
if ((p = checkstring(cmdline, (unsigned char * )
|
|
"OPEN")) != NULL)
|
|
i2cEnable(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"CLOSE")) != NULL)
|
|
i2cDisable(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"WRITE")) != NULL)
|
|
i2cSend(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"READ")) != NULL)
|
|
i2cReceive(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"CHECK")) != NULL)
|
|
i2cCheck(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"SLAVE OPEN")) != NULL)
|
|
i2cSlave(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"SLAVE READ")) != NULL)
|
|
i2cReceiveSlave(p, 0);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"SLAVE WRITE")) != NULL)
|
|
i2cSendSlave(p, 0);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"SLAVE CLOSE")) != NULL)
|
|
i2cDisable(p);
|
|
else
|
|
error("Unknown command");
|
|
}
|
|
void cmd_i2c2(void) {
|
|
unsigned char * p; //, *pp;
|
|
if (I2C1SDApin == 99 || I2C1SCLpin == 99) error("Pin not set for I2C2");
|
|
|
|
if ((p = checkstring(cmdline, (unsigned char * )
|
|
"OPEN")) != NULL)
|
|
i2c2Enable(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"CLOSE")) != NULL)
|
|
i2c2Disable(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"WRITE")) != NULL)
|
|
i2c2Send(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"READ")) != NULL)
|
|
i2c2Receive(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"CHECK")) != NULL)
|
|
i2c2Check(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"SLAVE OPEN")) != NULL)
|
|
i2c2Slave(p);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"SLAVE READ")) != NULL)
|
|
i2cReceiveSlave(p, 1);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"SLAVE WRITE")) != NULL)
|
|
i2cSendSlave(p, 1);
|
|
else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"SLAVE CLOSE")) != NULL)
|
|
i2c2Disable(p);
|
|
else
|
|
error("Unknown command");
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
void __not_in_flash_func(i2c0_irq_handler)(void) {
|
|
// Get interrupt status
|
|
uint32_t status = i2c0 -> hw -> intr_stat;
|
|
//is a write request? Or a read request ? event
|
|
if (status & I2C_IC_INTR_STAT_R_RX_FULL_BITS) {
|
|
i2c0 -> hw -> intr_mask = I2C_IC_INTR_MASK_M_RD_REQ_BITS;
|
|
I2C_Status |= I2C_Status_Slave_Receive_Rdy;
|
|
} else if (status & I2C_IC_INTR_STAT_R_RD_REQ_BITS) {
|
|
i2c0 -> hw -> clr_rd_req;
|
|
I2C_Status |= I2C_Status_Slave_Send_Rdy;
|
|
}
|
|
}
|
|
void __not_in_flash_func(i2c1_irq_handler)(void) {
|
|
// Get interrupt status
|
|
uint32_t status = i2c1 -> hw -> intr_stat;
|
|
//is a write request? Or a read request ? event
|
|
if (status & I2C_IC_INTR_STAT_R_RX_FULL_BITS) {
|
|
i2c1 -> hw -> intr_mask = I2C_IC_INTR_MASK_M_RD_REQ_BITS;
|
|
I2C2_Status |= I2C_Status_Slave_Receive_Rdy;
|
|
} else if (status & I2C_IC_INTR_STAT_R_RD_REQ_BITS) {
|
|
i2c1 -> hw -> clr_rd_req;
|
|
I2C2_Status |= I2C_Status_Slave_Send_Rdy;
|
|
}
|
|
}
|
|
void i2cSlave(unsigned char * p) {
|
|
int addr;
|
|
getargs( & p, 5, (unsigned char * )
|
|
",");
|
|
if (argc != 5) error("Argument count");
|
|
if (I2C_Status & I2C_Status_Slave) error("Slave already open");
|
|
addr = getinteger(argv[0]);
|
|
ExtCfg(I2C0SDApin, EXT_COM_RESERVED, 0);
|
|
ExtCfg(I2C0SCLpin, EXT_COM_RESERVED, 0);
|
|
gpio_pull_up(PinDef[I2C0SDApin].GPno);
|
|
gpio_pull_up(PinDef[I2C0SCLpin].GPno);
|
|
i2c_init(i2c0, 400000);
|
|
I2C_Slave_Addr = addr;
|
|
I2C_Slave_Send_IntLine = (char * ) GetIntAddress(argv[2]); // get the interrupt routine's location
|
|
I2C_Slave_Receive_IntLine = (char * ) GetIntAddress(argv[4]); // get the interrupt routine's location
|
|
InterruptUsed = true;
|
|
i2c_set_slave_mode(i2c0, true, I2C_Slave_Addr);
|
|
// Enable the I2C interrupts we want to process
|
|
i2c0 -> hw -> intr_mask = I2C_IC_INTR_STAT_R_RX_FULL_BITS | I2C_IC_INTR_MASK_M_RD_REQ_BITS;
|
|
|
|
// Set up the interrupt handler to service I2C interrupts
|
|
irq_set_exclusive_handler(I2C0_IRQ, i2c0_irq_handler);
|
|
irq_set_enabled(I2C0_IRQ, true);
|
|
I2C_Status = I2C_Status_Slave;
|
|
|
|
}
|
|
void i2c2Slave(unsigned char * p) {
|
|
int addr;
|
|
getargs( & p, 5, (unsigned char * )
|
|
",");
|
|
if (argc != 5) error("Argument count");
|
|
if (I2C2_Status & I2C_Status_Slave) error("Slave already open");
|
|
addr = getinteger(argv[0]);
|
|
ExtCfg(I2C1SDApin, EXT_COM_RESERVED, 0);
|
|
ExtCfg(I2C1SCLpin, EXT_COM_RESERVED, 0);
|
|
gpio_pull_up(PinDef[I2C1SDApin].GPno);
|
|
gpio_pull_up(PinDef[I2C1SCLpin].GPno);
|
|
i2c_init(i2c1, 400000);
|
|
I2C2_Slave_Addr = addr;
|
|
I2C2_Slave_Send_IntLine = (char * ) GetIntAddress(argv[2]); // get the interrupt routine's location
|
|
I2C2_Slave_Receive_IntLine = (char * ) GetIntAddress(argv[4]); // get the interrupt routine's location
|
|
InterruptUsed = true;
|
|
i2c_set_slave_mode(i2c1, true, I2C2_Slave_Addr);
|
|
// Enable the I2C interrupts we want to process
|
|
i2c1 -> hw -> intr_mask = I2C_IC_INTR_STAT_R_RX_FULL_BITS | I2C_IC_INTR_MASK_M_RD_REQ_BITS;
|
|
|
|
// Set up the interrupt handler to service I2C interrupts
|
|
irq_set_exclusive_handler(I2C1_IRQ, i2c1_irq_handler);
|
|
irq_set_enabled(I2C1_IRQ, true);
|
|
I2C2_Status = I2C_Status_Slave;
|
|
|
|
}
|
|
int DoRtcI2C(int addr, unsigned char * buff) {
|
|
if (I2C0locked) {
|
|
I2C_Addr = addr; // address of the device
|
|
i2c_masterCommand(1, buff);
|
|
} else {
|
|
I2C2_Addr = addr; // address of the device
|
|
i2c2_masterCommand(1, buff);
|
|
}
|
|
return !mmI2Cvalue;
|
|
}
|
|
#ifndef USBKEYBOARD
|
|
void CheckI2CKeyboard(int noerror, int read) {
|
|
uint16_t buff;
|
|
// int readover=0;
|
|
static int ctrlheld = 0;
|
|
// while(readover==0){
|
|
if (I2C0locked) {
|
|
if (read == 0) {
|
|
I2C_Sendlen = 1; // send one byte
|
|
I2C_Rcvlen = 0;
|
|
I2C_Status = 0;
|
|
I2C_Send_Buffer[0] = 9; // the first register to read
|
|
if (!(DoRtcI2C(0x1F, NULL))) goto i2c_error_exit;
|
|
} else {
|
|
I2C_Rcvbuf_String = (char * ) & buff; // we want a string of bytes
|
|
I2C_Rcvbuf_Float = NULL;
|
|
I2C_Rcvbuf_Int = NULL;
|
|
I2C_Rcvlen = 2; // get 7 bytes
|
|
I2C_Sendlen = 0;
|
|
if (!DoRtcI2C(0x1F, (unsigned char * ) & buff)) goto i2c_error_exit;
|
|
}
|
|
} else {
|
|
I2C2_Sendlen = 1; // send one byte
|
|
I2C2_Rcvlen = 0;
|
|
I2C2_Status = 0;
|
|
I2C_Send_Buffer[0] = 9; // the first register to read
|
|
if (!(DoRtcI2C(0x1F, NULL))) goto i2c_error_exit;
|
|
I2C2_Rcvbuf_String = (char * ) & buff; // we want a string of bytes
|
|
I2C2_Rcvbuf_Float = NULL;
|
|
I2C2_Rcvbuf_Int = NULL;
|
|
I2C2_Rcvlen = 2; // get 7 bytes
|
|
I2C2_Sendlen = 0;
|
|
if (!DoRtcI2C(0x1F, (unsigned char * ) & buff)) goto i2c_error_exit;
|
|
}
|
|
uSec(1000);
|
|
if (buff) {
|
|
#ifdef PICOCALC
|
|
if (buff == 0xA503) ctrlheld = 0;
|
|
else if (buff == 0xA502) {
|
|
ctrlheld=1;
|
|
} else if((buff & 0xff) == 1) { //pressed
|
|
int c = buff >> 8;
|
|
int realc = 0;
|
|
switch(c) {
|
|
// Refer to Appendix H in PicoMite User Manual
|
|
// PicoCalc must be mapped to expected PicoMite keys
|
|
case 0xd4:
|
|
realc=DEL; break;
|
|
case 0xb5:
|
|
realc=UP; break;
|
|
case 0xb6:
|
|
realc=DOWN; break;
|
|
case 0xb4:
|
|
realc=LEFT; break;
|
|
case 0xb7:
|
|
realc=RIGHT; break;
|
|
case 0xd1:
|
|
realc=INSERT; break; // ALT + I
|
|
case 0xd2:
|
|
realc=HOME; break; // SHIFT + TAB (collision, see below)
|
|
case 0xd5:
|
|
realc=END; break; // SHIFT + DEL (collision, see below)
|
|
case 0xd6:
|
|
realc=PUP; break; // SHIFT + UP
|
|
case 0xd7:
|
|
realc=PDOWN; break; // SHIFT + DOWN (collision, see below)
|
|
case 0xa1:
|
|
realc=ALT; break; // Note: SHIFT + ENTER also sends ALT!
|
|
case 0x81:
|
|
realc=F1; break;
|
|
case 0x82:
|
|
realc=F2; break;
|
|
case 0x83:
|
|
realc=F3; break;
|
|
case 0x84:
|
|
realc=F4; break;
|
|
case 0x85:
|
|
realc=F5; break;
|
|
case 0x86:
|
|
realc=F6; break; // SHIFT + F1
|
|
case 0x87:
|
|
realc=F7; break; // SHIFT + F2
|
|
case 0x88:
|
|
realc=F8; break; // SHIFT + F3
|
|
case 0x89:
|
|
realc=F9; break; // SHIFT + F4
|
|
case 0x90:
|
|
realc=F10; break; // SHIFT + F5
|
|
// F11 not on PicoCalc
|
|
// F12 not on PicoCalc
|
|
// PrtScr/SysRq not on PicoCalc
|
|
case 0xd0:
|
|
realc=BreakKey; break;
|
|
// SHIFT_TAB sends Home on PicoCalc
|
|
// SHIFT_DEL sends End on PicoCalc
|
|
// DOWNSEL (SHIFT_DOWN_ARROW) sends Page Down (PDOWN) on PicoCalc
|
|
// Note: (SHIFT_UP_ARROW) sends Page Up (PUP) on PicoCalc
|
|
// RIGHTSEL (SHIFT_RIGHT_ARROW) sends nothing on PicoCalc
|
|
// Note: (SHIFT_LEFT_ARROW) sends nothing on PicoCalc
|
|
// Note: PicoCalc cannot send shifted Fn keys!
|
|
// --- Appendix H ends
|
|
case 0xb1:
|
|
realc=ESC; break;
|
|
case 0x0a:
|
|
realc=ENTER; break;
|
|
// --- Modifier keys must be consumed and ignored!
|
|
case 0xa2: // Shift (left)
|
|
case 0xa3: // Shift (right)
|
|
case 0xa5: // Ctrl
|
|
case 0xc1: // CapsLK
|
|
return;
|
|
default:
|
|
realc = c; break;
|
|
}
|
|
c = realc;
|
|
#else
|
|
if (buff == 0x1203) ctrlheld = 0;
|
|
else if (buff == 0x1202) {
|
|
ctrlheld = 1;
|
|
} else if ((buff & 0xff) == 1) {
|
|
int c = buff >> 8;
|
|
if (c == 6) c = ESC;
|
|
if (c == 0x11) c = F1;
|
|
if (c == 5) c = F2;
|
|
if (c == 0x7) c = F4;
|
|
#endif
|
|
if (c >= 'a' && c <= 'z' && ctrlheld) c = c - 'a' + 1;
|
|
if (c == BreakKey) { // if the user wants to stop the progran
|
|
MMAbort = true; // set the flag for the interpreter to see
|
|
ConsoleRxBufHead = ConsoleRxBufTail; // empty the buffer
|
|
// break;
|
|
} else {
|
|
ConsoleRxBuf[ConsoleRxBufHead] = c; // store the byte in the ring buffer
|
|
if (ConsoleRxBuf[ConsoleRxBufHead] == keyselect && KeyInterrupt != NULL) {
|
|
Keycomplete = true;
|
|
} else {
|
|
ConsoleRxBufHead = (ConsoleRxBufHead + 1) % CONSOLE_RX_BUF_SIZE; // advance the head of the queue
|
|
if (ConsoleRxBufHead == ConsoleRxBufTail) { // if the buffer has overflowed
|
|
ConsoleRxBufTail = (ConsoleRxBufTail + 1) % CONSOLE_RX_BUF_SIZE; // throw away the oldest char
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// } else readover=1;
|
|
}
|
|
return;
|
|
i2c_error_exit:
|
|
if (noerror) {
|
|
noI2C = 1;
|
|
return;
|
|
}
|
|
if (CurrentLinePtr) error("I2C Keyboard not responding");
|
|
if (Option.KeyboardConfig == CONFIG_I2C) {
|
|
MMPrintString("I2C Keyboard not responding");
|
|
MMPrintString("\r\n");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void RtcGetTime(int noerror) {
|
|
char * buff = GetTempMemory(STRINGSIZE); // Received data is stored here
|
|
int DS1307;
|
|
if (I2C0locked) {
|
|
I2C_Sendlen = 1; // send one byte
|
|
I2C_Rcvlen = 0;
|
|
I2C_Status = 0;
|
|
I2C_Send_Buffer[0] = 0; // the first register to read
|
|
if (!(DS1307 = DoRtcI2C(0x68, NULL))) {
|
|
I2C_Send_Buffer[0] = 2; // the first register is different for the PCF8563
|
|
if (!DoRtcI2C(0x51, NULL)) goto error_exit;
|
|
}
|
|
I2C_Rcvbuf_String = buff; // we want a string of bytes
|
|
I2C_Rcvbuf_Float = NULL;
|
|
I2C_Rcvbuf_Int = NULL;
|
|
I2C_Rcvlen = 7; // get 7 bytes
|
|
I2C_Sendlen = 0;
|
|
if (!DoRtcI2C(DS1307 ? 0x68 : 0x51, (unsigned char * ) buff)) goto error_exit;
|
|
} else {
|
|
I2C2_Sendlen = 1; // send one byte
|
|
I2C2_Rcvlen = 0;
|
|
I2C2_Status = 0;
|
|
I2C_Send_Buffer[0] = 0; // the first register to read
|
|
if (!(DS1307 = DoRtcI2C(0x68, NULL))) {
|
|
I2C_Send_Buffer[0] = 2; // the first register is different for the PCF8563
|
|
if (!DoRtcI2C(0x51, NULL)) goto error_exit;
|
|
}
|
|
I2C2_Rcvbuf_String = buff; // we want a string of bytes
|
|
I2C2_Rcvbuf_Float = NULL;
|
|
I2C2_Rcvbuf_Int = NULL;
|
|
I2C2_Rcvlen = 7; // get 7 bytes
|
|
I2C2_Sendlen = 0;
|
|
if (!DoRtcI2C(DS1307 ? 0x68 : 0x51, (unsigned char * ) buff)) goto error_exit;
|
|
}
|
|
// mT4IntEnable(0);
|
|
int year, month, day, hour, minute, second;
|
|
second = ((buff[0] & 0x7f) >> 4) * 10 + (buff[0] & 0x0f);
|
|
minute = ((buff[1] & 0x7f) >> 4) * 10 + (buff[1] & 0x0f);
|
|
hour = ((buff[2] & 0x3f) >> 4) * 10 + (buff[2] & 0x0f);
|
|
day = ((buff[DS1307 ? 4 : 3] & 0x3f) >> 4) * 10 + (buff[DS1307 ? 4 : 3] & 0x0f);
|
|
month = ((buff[5] & 0x1f) >> 4) * 10 + (buff[5] & 0x0f);
|
|
year = (buff[6] >> 4) * 10 + (buff[6] & 0x0f) + 2000;
|
|
// mT4IntEnable(1);
|
|
TimeOffsetToUptime = get_epoch(year, month, day, hour, minute, second) - time_us_64() / 1000000;
|
|
return;
|
|
|
|
error_exit:
|
|
if (noerror) {
|
|
noRTC = 1;
|
|
return;
|
|
}
|
|
if (CurrentLinePtr) error("RTC not responding");
|
|
if (Option.RTC) {
|
|
MMPrintString("RTC not responding");
|
|
MMPrintString("\r\n");
|
|
}
|
|
}
|
|
// universal function to send/receive data to/from the RTC
|
|
// addr is the I2C address WITHOUT the read/write bit
|
|
char CvtToBCD(unsigned char * p, int min, int max) {
|
|
long long int t;
|
|
t = getint(p, min, max) % 100;
|
|
return ((t / 10) << 4) | (t % 10);
|
|
}
|
|
|
|
char CvtCharsToBCD(unsigned char * p, int min, int max) {
|
|
int t;
|
|
t = (p[0] - '0') * 10 + (p[1] - '0');
|
|
// dp("|%c| |%c| %d %d %d", p[0], p[1], t, min, max);
|
|
if (!isdigit(p[0]) || !isdigit(p[1]) || t < min || t > max) error("Date/time format");
|
|
return ((t / 10) << 4) | (t % 10);
|
|
}
|
|
|
|
/* @endcond */
|
|
void MIPS16 cmd_rtc(void) {
|
|
char buff[7]; // Received data is stored here
|
|
int DS1307;
|
|
unsigned char * p;
|
|
void * ptr = NULL;
|
|
if (!(I2C0locked || I2C1locked)) error("SYSTEM I2C not configured");
|
|
if (checkstring(cmdline, (unsigned char * )
|
|
"GETTIME")) {
|
|
RtcGetTime(0);
|
|
return;
|
|
}
|
|
if ((p = checkstring(cmdline, (unsigned char * )
|
|
"SETTIME")) != NULL) {
|
|
int Fulldate = 0;
|
|
getargs( & p, 11, (unsigned char * )
|
|
",");
|
|
if (I2C0locked) {
|
|
if (argc == 1) {
|
|
// single argument - assume the data is in DATETIME2 format used by GUI FORMATBOX
|
|
p = getCstring(argv[0]);
|
|
if (!(p[2] == '/' || p[2] == '-') || !(p[11] == ':' || p[13] == ':')) error("Date/time format");
|
|
if (p[13] == ':') Fulldate = 2;
|
|
if (p[14 + Fulldate] == ':')
|
|
I2C_Send_Buffer[1] = CvtCharsToBCD(p + 15 + Fulldate, 0, 59); // seconds
|
|
else
|
|
I2C_Send_Buffer[1] = 0; // seconds defaults to zero
|
|
I2C_Send_Buffer[2] = CvtCharsToBCD(p + 12 + Fulldate, 0, 59); // minutes
|
|
I2C_Send_Buffer[3] = CvtCharsToBCD(p + 9 + Fulldate, 0, 23); // hour
|
|
I2C_Send_Buffer[5] = CvtCharsToBCD(p, 1, 31); // day
|
|
I2C_Send_Buffer[6] = CvtCharsToBCD(p + 3, 1, 12); // month
|
|
I2C_Send_Buffer[7] = CvtCharsToBCD(p + 6 + Fulldate, 0, 99); // year
|
|
} else {
|
|
// multiple arguments - data should be in the original yy, mm, dd, etc format
|
|
if (argc != 11) error("Argument count");
|
|
I2C_Send_Buffer[1] = CvtToBCD(argv[10], 0, 59); // seconds
|
|
I2C_Send_Buffer[2] = CvtToBCD(argv[8], 0, 59); // minutes
|
|
I2C_Send_Buffer[3] = CvtToBCD(argv[6], 0, 23); // hour
|
|
I2C_Send_Buffer[5] = CvtToBCD(argv[4], 1, 31); // day
|
|
I2C_Send_Buffer[6] = CvtToBCD(argv[2], 1, 12); // month
|
|
I2C_Send_Buffer[7] = CvtToBCD(argv[0], 0, 2099); // year
|
|
}
|
|
I2C_Send_Buffer[0] = 0; // turn off the square wave
|
|
I2C_Send_Buffer[4] = 1;
|
|
I2C_Rcvlen = 0;
|
|
I2C_Sendlen = 9; // send 7 bytes
|
|
if (!DoRtcI2C(0x68, NULL)) {
|
|
I2C_Send_Buffer[9] = I2C_Send_Buffer[7]; // year
|
|
I2C_Send_Buffer[8] = I2C_Send_Buffer[6]; // month
|
|
I2C_Send_Buffer[7] = 1;
|
|
I2C_Send_Buffer[6] = I2C_Send_Buffer[5]; // day
|
|
I2C_Send_Buffer[5] = I2C_Send_Buffer[3]; // hour
|
|
I2C_Send_Buffer[4] = I2C_Send_Buffer[2]; // minutes
|
|
I2C_Send_Buffer[3] = I2C_Send_Buffer[1]; // seconds
|
|
I2C_Send_Buffer[0] = I2C_Send_Buffer[1] = I2C_Send_Buffer[2] = 0; // set the register pointer to the first register then zero the first two registers
|
|
I2C_Sendlen = 10; // send 10 bytes
|
|
if (!DoRtcI2C(0x51, NULL)) error("RTC not responding");
|
|
}
|
|
} else {
|
|
if (argc == 1) {
|
|
// single argument - assume the data is in DATETIME2 format used by GUI FORMATBOX
|
|
p = getCstring(argv[0]);
|
|
if (!(p[2] == '/' || p[2] == '-') || !(p[11] == ':' || p[13] == ':')) error("Date/time format");
|
|
if (p[13] == ':') Fulldate = 2;
|
|
if (p[14 + Fulldate] == ':')
|
|
I2C_Send_Buffer[1] = CvtCharsToBCD(p + 15 + Fulldate, 0, 59); // seconds
|
|
else
|
|
I2C_Send_Buffer[1] = 0; // seconds defaults to zero
|
|
I2C_Send_Buffer[2] = CvtCharsToBCD(p + 12 + Fulldate, 0, 59); // minutes
|
|
I2C_Send_Buffer[3] = CvtCharsToBCD(p + 9 + Fulldate, 0, 23); // hour
|
|
I2C_Send_Buffer[5] = CvtCharsToBCD(p, 1, 31); // day
|
|
I2C_Send_Buffer[6] = CvtCharsToBCD(p + 3, 1, 12); // month
|
|
I2C_Send_Buffer[7] = CvtCharsToBCD(p + 6 + Fulldate, 0, 99); // year
|
|
} else {
|
|
// multiple arguments - data should be in the original yy, mm, dd, etc format
|
|
if (argc != 11) error("Argument count");
|
|
I2C_Send_Buffer[1] = CvtToBCD(argv[10], 0, 59); // seconds
|
|
I2C_Send_Buffer[2] = CvtToBCD(argv[8], 0, 59); // minutes
|
|
I2C_Send_Buffer[3] = CvtToBCD(argv[6], 0, 23); // hour
|
|
I2C_Send_Buffer[5] = CvtToBCD(argv[4], 1, 31); // day
|
|
I2C_Send_Buffer[6] = CvtToBCD(argv[2], 1, 12); // month
|
|
I2C_Send_Buffer[7] = CvtToBCD(argv[0], 0, 2099); // year
|
|
}
|
|
I2C_Send_Buffer[0] = 0; // turn off the square wave
|
|
I2C_Send_Buffer[4] = 1;
|
|
I2C2_Rcvlen = 0;
|
|
I2C2_Sendlen = 9; // send 7 bytes
|
|
if (!DoRtcI2C(0x68, NULL)) {
|
|
I2C_Send_Buffer[9] = I2C_Send_Buffer[7]; // year
|
|
I2C_Send_Buffer[8] = I2C_Send_Buffer[6]; // month
|
|
I2C_Send_Buffer[7] = 1;
|
|
I2C_Send_Buffer[6] = I2C_Send_Buffer[5]; // day
|
|
I2C_Send_Buffer[5] = I2C_Send_Buffer[3]; // hour
|
|
I2C_Send_Buffer[4] = I2C_Send_Buffer[2]; // minutes
|
|
I2C_Send_Buffer[3] = I2C_Send_Buffer[1]; // seconds
|
|
I2C_Send_Buffer[0] = I2C_Send_Buffer[1] = I2C_Send_Buffer[2] = 0; // set the register pointer to the first register then zero the first two registers
|
|
I2C2_Sendlen = 10; // send 10 bytes
|
|
if (!DoRtcI2C(0x51, NULL)) error("RTC not responding");
|
|
}
|
|
}
|
|
RtcGetTime(0);
|
|
} else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"GETREG")) != NULL) {
|
|
getargs( & p, 3, (unsigned char * )
|
|
",");
|
|
if (argc != 3) error("Argument count");
|
|
if (I2C0locked) {
|
|
I2C_Sendlen = 1; // send one byte
|
|
I2C_Rcvlen = 0;
|
|
* I2C_Send_Buffer = getint(argv[0], 0, 255); // the register to read
|
|
} else {
|
|
I2C2_Sendlen = 1; // send one byte
|
|
I2C2_Rcvlen = 0;
|
|
* I2C_Send_Buffer = getint(argv[0], 0, 255); // the register to read
|
|
}
|
|
ptr = 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 (!(DS1307 = DoRtcI2C(0x68, NULL))) {
|
|
if (!DoRtcI2C(0x51, NULL)) error("RTC not responding");
|
|
}
|
|
if (I2C0locked) {
|
|
I2C_Rcvbuf_String = buff; // we want a string of bytes
|
|
I2C_Rcvbuf_Float = NULL;
|
|
I2C_Rcvbuf_Int = NULL;
|
|
I2C_Rcvlen = 1; // get 1 byte
|
|
I2C_Sendlen = 0;
|
|
} else {
|
|
I2C2_Rcvbuf_String = buff; // we want a string of bytes
|
|
I2C2_Rcvbuf_Float = NULL;
|
|
I2C2_Rcvbuf_Int = NULL;
|
|
I2C2_Rcvlen = 1; // get 1 byte
|
|
I2C2_Sendlen = 0;
|
|
}
|
|
if (!DoRtcI2C(DS1307 ? 0x68 : 0x51, (unsigned char * ) buff)) error("RTC not responding1");
|
|
if (g_vartbl[g_VarIndex].type & T_NBR)
|
|
*
|
|
(MMFLOAT * ) ptr = buff[0];
|
|
else
|
|
*
|
|
(long long int * ) ptr = buff[0];
|
|
} else if ((p = checkstring(cmdline, (unsigned char * )
|
|
"SETREG")) != NULL) {
|
|
getargs( & p, 3, (unsigned char * )
|
|
",");
|
|
if (argc != 3) error("Argument count");
|
|
if (I2C0locked) {
|
|
I2C_Rcvlen = 0;
|
|
I2C_Send_Buffer[0] = getint(argv[0], 0, 255); // set the register pointer
|
|
I2C_Send_Buffer[1] = getint(argv[2], 0, 255); // and the data to be written
|
|
I2C_Sendlen = 2; // send 2 bytes
|
|
} else {
|
|
I2C2_Rcvlen = 0;
|
|
I2C_Send_Buffer[0] = getint(argv[0], 0, 255); // set the register pointer
|
|
I2C_Send_Buffer[1] = getint(argv[2], 0, 255); // and the data to be written
|
|
I2C2_Sendlen = 2; // send 2 bytes
|
|
}
|
|
if (!DoRtcI2C(0x68, NULL)) {
|
|
if (!DoRtcI2C(0x51, NULL)) error("RTC not responding");
|
|
}
|
|
} else
|
|
error("Unknown command");
|
|
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
// enable the I2C1 module - master mode
|
|
void i2cEnable(unsigned char * p) {
|
|
int speed, timeout;
|
|
getargs( & p, 3, (unsigned char * )
|
|
",");
|
|
if (argc != 3) error("Invalid syntax");
|
|
speed = getinteger(argv[0]);
|
|
if (!(speed == 100 || speed == 400 || speed == 1000)) error("Valid speeds 100, 400, 1000");
|
|
timeout = getinteger(argv[2]);
|
|
if (timeout < 0 || (timeout > 0 && timeout < 100)) error("Number out of bounds");
|
|
if (I2C_enabled || I2C_Status & I2C_Status_Slave) error("I2C already OPEN");
|
|
I2C_Timeout = timeout;
|
|
i2c_enable(speed);
|
|
|
|
}
|
|
// enable the I2C1 module - master mode
|
|
void i2c2Enable(unsigned char * p) {
|
|
int speed, timeout;
|
|
getargs( & p, 3, (unsigned char * )
|
|
",");
|
|
if (argc != 3) error("Invalid syntax");
|
|
speed = getinteger(argv[0]);
|
|
if (!(speed == 100 || speed == 400 || speed == 1000)) error("Valid speeds 100, 400, 1000");
|
|
timeout = getinteger(argv[2]);
|
|
if (timeout < 0 || (timeout > 0 && timeout < 100)) error("Number out of bounds");
|
|
if (I2C2_enabled || I2C2_Status & I2C_Status_Slave) error("I2C already OPEN");
|
|
I2C2_Timeout = timeout;
|
|
i2c2_enable(speed);
|
|
|
|
}
|
|
|
|
// disable the I2C1 module - master mode
|
|
void i2cDisable(unsigned char * p) {
|
|
if (!I2C0locked) i2c_disable();
|
|
else error("Allocated to System I2C");
|
|
}
|
|
|
|
// disable the I2C1 module - master mode
|
|
void i2c2Disable(unsigned char * p) {
|
|
if (!I2C1locked) i2c2_disable();
|
|
else error("Allocated to System I2C");
|
|
}
|
|
|
|
// send data to an I2C slave - master mode
|
|
void i2cSend(unsigned char * p) {
|
|
int addr, i2c_options, sendlen, i;
|
|
void * ptr = NULL;
|
|
unsigned char * cptr = NULL;
|
|
|
|
getargs( & p, 99, (unsigned char * )
|
|
",");
|
|
if (!(argc & 0x01) || (argc < 7)) error("Invalid syntax");
|
|
if (!I2C_enabled) error("I2C not open");
|
|
addr = getinteger(argv[0]);
|
|
i2c_options = getinteger(argv[2]);
|
|
if (i2c_options < 0 || i2c_options > 3) error("Number out of bounds");
|
|
I2C_Status = 0;
|
|
if (i2c_options & 0x01) I2C_Status = I2C_Status_BusHold;
|
|
I2C_Addr = addr;
|
|
sendlen = getint(argv[4], 1, 256);
|
|
|
|
if (sendlen == 1 || argc > 7) { // numeric expressions for data
|
|
if (sendlen != ((argc - 5) >> 1)) error("Incorrect argument count");
|
|
for (i = 0; i < sendlen; i++) {
|
|
I2C_Send_Buffer[i] = getinteger(argv[i + i + 6]);
|
|
}
|
|
} else { // an array of MMFLOAT, integer or a string
|
|
ptr = findvar(argv[6], V_NOFIND_NULL | V_EMPTY_OK);
|
|
if (ptr == NULL) error("Invalid variable");
|
|
if ((g_vartbl[g_VarIndex].type & T_STR) && g_vartbl[g_VarIndex].dims[0] == 0) { // string
|
|
if (sendlen > 255) error("Number out of bounds");
|
|
cptr = (unsigned char * ) ptr;
|
|
cptr++; // skip the length byte in a MMBasic string
|
|
for (i = 0; i < sendlen; i++) {
|
|
I2C_Send_Buffer[i] = (int)( * (cptr + i));
|
|
}
|
|
} else if ((g_vartbl[g_VarIndex].type & T_NBR) && g_vartbl[g_VarIndex].dims[0] > 0 && g_vartbl[g_VarIndex].dims[1] == 0) { // numeric array
|
|
if ((((MMFLOAT * ) ptr - g_vartbl[g_VarIndex].val.fa) + sendlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase)) {
|
|
error("Insufficient data");
|
|
} else {
|
|
for (i = 0; i < sendlen; i++) {
|
|
I2C_Send_Buffer[i] = (int)( * ((MMFLOAT * ) ptr + i));
|
|
}
|
|
}
|
|
} else if ((g_vartbl[g_VarIndex].type & T_INT) && g_vartbl[g_VarIndex].dims[0] > 0 && g_vartbl[g_VarIndex].dims[1] == 0) { // integer array
|
|
if ((((long long int * ) ptr - g_vartbl[g_VarIndex].val.ia) + sendlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase)) {
|
|
error("Insufficient data");
|
|
} else {
|
|
for (i = 0; i < sendlen; i++) {
|
|
I2C_Send_Buffer[i] = (int)( * ((long long int * ) ptr + i));
|
|
}
|
|
}
|
|
} else error("Invalid variable");
|
|
}
|
|
I2C_Sendlen = sendlen;
|
|
I2C_Rcvlen = 0;
|
|
|
|
i2c_masterCommand(1, NULL);
|
|
}
|
|
// send data to an I2C slave - master mode
|
|
void i2cSendSlave(unsigned char * p, int channel) {
|
|
int sendlen, i;
|
|
void * ptr = NULL;
|
|
unsigned char * cptr = NULL;
|
|
getargs( & p, 99, (unsigned char * )
|
|
",");
|
|
if (!(argc >= 3)) error("Invalid syntax");
|
|
if (!((I2C_Status & I2C_Status_Slave && channel == 0) || (I2C2_Status & I2C_Status_Slave && channel == 1))) error("I2C slave not open");
|
|
unsigned char * bbuff;
|
|
if (channel == 0) {
|
|
bbuff = I2C_Send_Buffer;
|
|
} else {
|
|
bbuff = I2C_Send_Buffer;
|
|
}
|
|
sendlen = getinteger(argv[0]);
|
|
if (sendlen < 1 || sendlen > 255) error("Number out of bounds");
|
|
|
|
if (sendlen == 1 || argc > 3) { // numeric expressions for data
|
|
if (sendlen != ((argc - 1) >> 1)) error("Incorrect argument count");
|
|
for (i = 0; i < sendlen; i++) {
|
|
bbuff[i] = getinteger(argv[i + i + 2]);
|
|
}
|
|
} else { // an array of MMFLOAT, integer or a string
|
|
ptr = findvar(argv[2], V_NOFIND_NULL | V_EMPTY_OK);
|
|
if (ptr == NULL) error("Invalid variable");
|
|
if ((g_vartbl[g_VarIndex].type & T_STR) && g_vartbl[g_VarIndex].dims[0] == 0) { // string
|
|
cptr = (unsigned char * ) ptr;
|
|
cptr++; // skip the length byte in a MMBasic string
|
|
for (i = 0; i < sendlen; i++) {
|
|
bbuff[i] = (int)( * (cptr + i));
|
|
}
|
|
} else if ((g_vartbl[g_VarIndex].type & T_NBR) && g_vartbl[g_VarIndex].dims[0] > 0 && g_vartbl[g_VarIndex].dims[1] == 0) { // numeric array
|
|
if ((((MMFLOAT * ) ptr - g_vartbl[g_VarIndex].val.fa) + sendlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase)) {
|
|
error("Insufficient data");
|
|
} else {
|
|
for (i = 0; i < sendlen; i++) {
|
|
bbuff[i] = (int)( * ((MMFLOAT * ) ptr + i));
|
|
}
|
|
}
|
|
} else if ((g_vartbl[g_VarIndex].type & T_INT) && g_vartbl[g_VarIndex].dims[0] > 0 && g_vartbl[g_VarIndex].dims[1] == 0) { // integer array
|
|
if ((((long long int * ) ptr - g_vartbl[g_VarIndex].val.ia) + sendlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase)) {
|
|
error("Insufficient data");
|
|
} else {
|
|
for (i = 0; i < sendlen; i++) {
|
|
bbuff[i] = (int)( * ((long long int * ) ptr + i));
|
|
}
|
|
}
|
|
} else error("Invalid variable");
|
|
}
|
|
if (channel == 0) i2c_write_raw_blocking(i2c0, bbuff, sendlen);
|
|
else i2c_write_raw_blocking(i2c1, bbuff, sendlen);
|
|
}
|
|
// send data to an I2C slave - master mode
|
|
void i2c2Send(unsigned char * p) {
|
|
int addr, i2c2_options, sendlen, i;
|
|
void * ptr = NULL;
|
|
unsigned char * cptr = NULL;
|
|
|
|
getargs( & p, 99, (unsigned char * )
|
|
",");
|
|
if (!(argc & 0x01) || (argc < 7)) error("Invalid syntax");
|
|
if (!I2C2_enabled) error("I2C not open");
|
|
addr = getinteger(argv[0]);
|
|
i2c2_options = getinteger(argv[2]);
|
|
if (i2c2_options < 0 || i2c2_options > 3) error("Number out of bounds");
|
|
I2C2_Status = 0;
|
|
if (i2c2_options & 0x01) I2C2_Status = I2C_Status_BusHold;
|
|
I2C2_Addr = addr;
|
|
sendlen = getint(argv[4], 1, 256);
|
|
|
|
if (sendlen == 1 || argc > 7) { // numeric expressions for data
|
|
if (sendlen != ((argc - 5) >> 1)) error("Incorrect argument count");
|
|
for (i = 0; i < sendlen; i++) {
|
|
I2C_Send_Buffer[i] = getinteger(argv[i + i + 6]);
|
|
}
|
|
} else { // an array of MMFLOAT, integer or a string
|
|
ptr = findvar(argv[6], V_NOFIND_NULL | V_EMPTY_OK);
|
|
if (ptr == NULL) error("Invalid variable");
|
|
if ((g_vartbl[g_VarIndex].type & T_STR) && g_vartbl[g_VarIndex].dims[0] == 0) { // string
|
|
if (sendlen > 255) error("Number out of bounds");
|
|
cptr = (unsigned char * ) ptr;
|
|
cptr++; // skip the length byte in a MMBasic string
|
|
for (i = 0; i < sendlen; i++) {
|
|
I2C_Send_Buffer[i] = (int)( * (cptr + i));
|
|
}
|
|
} else if ((g_vartbl[g_VarIndex].type & T_NBR) && g_vartbl[g_VarIndex].dims[0] > 0 && g_vartbl[g_VarIndex].dims[1] == 0) { // numeric array
|
|
if ((((MMFLOAT * ) ptr - g_vartbl[g_VarIndex].val.fa) + sendlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase)) {
|
|
error("Insufficient data");
|
|
} else {
|
|
for (i = 0; i < sendlen; i++) {
|
|
I2C_Send_Buffer[i] = (int)( * ((MMFLOAT * ) ptr + i));
|
|
}
|
|
}
|
|
} else if ((g_vartbl[g_VarIndex].type & T_INT) && g_vartbl[g_VarIndex].dims[0] > 0 && g_vartbl[g_VarIndex].dims[1] == 0) { // integer array
|
|
if ((((long long int * ) ptr - g_vartbl[g_VarIndex].val.ia) + sendlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase)) {
|
|
error("Insufficient data");
|
|
} else {
|
|
for (i = 0; i < sendlen; i++) {
|
|
I2C_Send_Buffer[i] = (int)( * ((long long int * ) ptr + i));
|
|
}
|
|
}
|
|
} else error("Invalid variable");
|
|
}
|
|
I2C2_Sendlen = sendlen;
|
|
I2C2_Rcvlen = 0;
|
|
|
|
i2c2_masterCommand(1, NULL);
|
|
}
|
|
|
|
void i2cCheck(unsigned char * p) {
|
|
int addr;
|
|
uint8_t rxdata;
|
|
getargs( & p, 1, (unsigned char * )
|
|
",");
|
|
if (!I2C_enabled) error("I2C not open");
|
|
addr = getinteger(argv[0]);
|
|
if (addr < 0 || addr > 0x7F) error("Invalid I2C address");
|
|
// int ret=i2c_read_blocking(i2c0, addr, &rxdata, 1, false);
|
|
int ret = i2c_read_timeout_us(i2c0, addr, & rxdata, 1, false, 100);
|
|
mmI2Cvalue = ret < 0 ? 1 : 0;
|
|
}
|
|
void i2c2Check(unsigned char * p) {
|
|
int addr;
|
|
uint8_t rxdata;
|
|
getargs( & p, 1, (unsigned char * )
|
|
",");
|
|
if (!I2C2_enabled) error("I2C not open");
|
|
addr = getinteger(argv[0]);
|
|
if (addr < 0 || addr > 0x7F) error("Invalid I2C address");
|
|
// int ret=i2c_read_blocking(i2c1, addr, &rxdata, 1, false);
|
|
int ret = i2c_read_timeout_us(i2c1, addr, & rxdata, 1, false, 100);
|
|
mmI2Cvalue = ret < 0 ? 1 : 0;
|
|
}
|
|
// receive data from an I2C slave - master mode
|
|
void i2cReceive(unsigned char * p) {
|
|
int addr, i2c_options, rcvlen;
|
|
void * ptr = NULL;
|
|
getargs( & p, 7, (unsigned char * )
|
|
",");
|
|
if (argc != 7) error("Invalid syntax");
|
|
if (!I2C_enabled) error("I2C not open");
|
|
addr = getinteger(argv[0]);
|
|
i2c_options = getint(argv[2], 0, 1);
|
|
I2C_Status = 0;
|
|
I2C_Rcvbuf_Float = NULL;
|
|
I2C_Rcvbuf_Int = NULL;
|
|
I2C_Rcvbuf_String = NULL;
|
|
if (i2c_options & 0x01) I2C_Status = I2C_Status_BusHold;
|
|
I2C_Addr = addr;
|
|
rcvlen = getinteger(argv[4]);
|
|
if (rcvlen < 1) error("Number out of bounds");
|
|
ptr = findvar(argv[6], V_FIND | V_EMPTY_OK);
|
|
if (g_vartbl[g_VarIndex].type & T_CONST) error("Cannot change a constant");
|
|
if (ptr == NULL) error("Invalid variable");
|
|
if (g_vartbl[g_VarIndex].type & T_NBR) {
|
|
if (g_vartbl[g_VarIndex].dims[1] != 0) error("Invalid variable");
|
|
if (g_vartbl[g_VarIndex].dims[0] <= 0) { // Not an array
|
|
if (rcvlen != 1) error("Invalid variable");
|
|
} else { // An array
|
|
if ((((MMFLOAT * ) ptr - g_vartbl[g_VarIndex].val.fa) + rcvlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase))
|
|
error("Insufficient space in array");
|
|
}
|
|
I2C_Rcvbuf_Float = (MMFLOAT * ) ptr;
|
|
} else if (g_vartbl[g_VarIndex].type & T_INT) {
|
|
if (g_vartbl[g_VarIndex].dims[1] != 0) error("Invalid variable");
|
|
if (g_vartbl[g_VarIndex].dims[0] <= 0) { // Not an array
|
|
if (rcvlen != 1) error("Invalid variable");
|
|
} else { // An array
|
|
if ((((long long int * ) ptr - g_vartbl[g_VarIndex].val.ia) + rcvlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase))
|
|
error("Insufficient space in array");
|
|
}
|
|
I2C_Rcvbuf_Int = (long long int * ) ptr;
|
|
} else if (g_vartbl[g_VarIndex].type & T_STR) {
|
|
if (rcvlen < 1 || rcvlen > 255) error("Number out of bounds");
|
|
if (g_vartbl[g_VarIndex].dims[0] != 0) error("Invalid variable");
|
|
*(char * ) ptr = rcvlen;
|
|
I2C_Rcvbuf_String = (char * ) ptr + 1;
|
|
} else error("Invalid variable");
|
|
I2C_Rcvlen = rcvlen;
|
|
|
|
I2C_Sendlen = 0;
|
|
char * buff = GetTempMemory(rcvlen > 255 ? rcvlen + 2 : STRINGSIZE);
|
|
// PInt((uint32_t)I2C_Rcvbuf_String);
|
|
i2c_masterCommand(1, (unsigned char * ) buff);
|
|
// PIntComma(rcvlen);
|
|
// PInt((uint32_t)I2C_Rcvbuf_String);PRet();
|
|
// if(g_vartbl[g_VarIndex].type & T_STR)*(char *)ptr = rcvlen;
|
|
}
|
|
void i2cReceiveSlave(unsigned char * p, int channel) {
|
|
int rcvlen;
|
|
void * ptr = NULL;
|
|
MMFLOAT * rcvdlenFloat = NULL;
|
|
long long int * rcvdlenInt = NULL;
|
|
int count = 1;
|
|
I2C_Rcvbuf_Float = NULL;
|
|
I2C_Rcvbuf_Int = NULL;
|
|
I2C_Rcvbuf_String = NULL;
|
|
I2C2_Rcvbuf_Float = NULL;
|
|
I2C2_Rcvbuf_Int = NULL;
|
|
I2C2_Rcvbuf_String = NULL;
|
|
getargs( & p, 5, (unsigned char * )
|
|
",");
|
|
if (argc != 5) error("Invalid syntax");
|
|
if (!((I2C_Status & I2C_Status_Slave && channel == 0) || (I2C2_Status & I2C_Status_Slave && channel == 1))) error("I2C slave not open");
|
|
rcvlen = getinteger(argv[0]);
|
|
if (rcvlen < 1 || rcvlen > 255) error("Number out of bounds");
|
|
ptr = findvar(argv[2], V_FIND | V_EMPTY_OK);
|
|
if (g_vartbl[g_VarIndex].type & T_CONST) error("Cannot change a constant");
|
|
if (ptr == NULL) error("Invalid variable");
|
|
if (g_vartbl[g_VarIndex].type & T_NBR) {
|
|
if (g_vartbl[g_VarIndex].dims[1] != 0) error("Invalid variable");
|
|
if (g_vartbl[g_VarIndex].dims[0] <= 0) { // Not an array
|
|
if (rcvlen != 1) error("Invalid variable");
|
|
} else { // An array
|
|
if ((((MMFLOAT * ) ptr - g_vartbl[g_VarIndex].val.fa) + rcvlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase))
|
|
error("Insufficient space in array");
|
|
}
|
|
I2C_Rcvbuf_Float = (MMFLOAT * ) ptr;
|
|
} else if (g_vartbl[g_VarIndex].type & T_INT) {
|
|
if (g_vartbl[g_VarIndex].dims[1] != 0) error("Invalid variable");
|
|
if (g_vartbl[g_VarIndex].dims[0] <= 0) { // Not an array
|
|
if (rcvlen != 1) error("Invalid variable");
|
|
} else { // An array
|
|
if ((((long long int * ) ptr - g_vartbl[g_VarIndex].val.ia) + rcvlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase))
|
|
error("Insufficient space in array");
|
|
}
|
|
I2C_Rcvbuf_Int = (long long int * ) ptr;
|
|
} else if (g_vartbl[g_VarIndex].type & T_STR) {
|
|
if (g_vartbl[g_VarIndex].dims[0] != 0) error("Invalid variable");
|
|
*(char * ) ptr = rcvlen;
|
|
I2C_Rcvbuf_String = (char * ) ptr + 1;
|
|
} else error("Invalid variable");
|
|
ptr = findvar(argv[4], V_FIND);
|
|
if (g_vartbl[g_VarIndex].type & T_CONST) error("Cannot change a constant");
|
|
if (g_vartbl[g_VarIndex].type & T_NBR) rcvdlenFloat = (MMFLOAT * ) ptr;
|
|
else if (g_vartbl[g_VarIndex].type & T_INT) rcvdlenInt = (long long int * ) ptr;
|
|
else error("Invalid variable");
|
|
|
|
unsigned char * bbuff;
|
|
if (channel == 0) {
|
|
bbuff = I2C_Send_Buffer;
|
|
i2c_read_raw_blocking(i2c0, bbuff, 1);
|
|
if (rcvlen > 1) {
|
|
I2CTimer = 0;
|
|
while (count < rcvlen && I2CTimer < rcvlen / 10 + 2) {
|
|
if (i2c0 -> hw -> status & 8) i2c_read_raw_blocking(i2c0, & bbuff[count++], 1);
|
|
}
|
|
}
|
|
} else {
|
|
bbuff = I2C_Send_Buffer;
|
|
i2c_read_raw_blocking(i2c1, bbuff, 1);
|
|
if (rcvlen > 1) {
|
|
I2CTimer = 0;
|
|
while (count < rcvlen && I2CTimer < rcvlen / 10 + 2) {
|
|
if (i2c1 -> hw -> status & 8) i2c_read_raw_blocking(i2c1, & bbuff[count++], 1);
|
|
}
|
|
}
|
|
}
|
|
for (int i = 0; i < rcvlen; i++) {
|
|
if (I2C_Rcvbuf_String != NULL) {
|
|
* I2C_Rcvbuf_String = bbuff[i];
|
|
I2C_Rcvbuf_String++;
|
|
}
|
|
if (I2C_Rcvbuf_Float != NULL) {
|
|
* I2C_Rcvbuf_Float = bbuff[i];
|
|
I2C_Rcvbuf_Float++;
|
|
}
|
|
if (I2C_Rcvbuf_Int != NULL) {
|
|
* I2C_Rcvbuf_Int = bbuff[i];
|
|
I2C_Rcvbuf_Int++;
|
|
}
|
|
}
|
|
if (!(rcvdlenFloat == NULL))
|
|
*
|
|
rcvdlenFloat = (MMFLOAT) count;
|
|
else
|
|
*
|
|
rcvdlenInt = (long long int) count;
|
|
|
|
if (channel == 0) i2c0 -> hw -> intr_mask = I2C_IC_INTR_STAT_R_RX_FULL_BITS | I2C_IC_INTR_MASK_M_RD_REQ_BITS;
|
|
else i2c1 -> hw -> intr_mask = I2C_IC_INTR_STAT_R_RX_FULL_BITS | I2C_IC_INTR_MASK_M_RD_REQ_BITS;
|
|
}
|
|
// receive data from an I2C slave - master mode
|
|
void i2c2Receive(unsigned char * p) {
|
|
int addr, i2c2_options, rcvlen;
|
|
void * ptr = NULL;
|
|
getargs( & p, 7, (unsigned char * )
|
|
",");
|
|
if (argc != 7) error("Invalid syntax");
|
|
if (!I2C2_enabled) error("I2C not open");
|
|
addr = getinteger(argv[0]);
|
|
i2c2_options = getint(argv[2], 0, 1);
|
|
I2C2_Status = 0;
|
|
if (i2c2_options & 0x01) I2C2_Status = I2C_Status_BusHold;
|
|
I2C2_Addr = addr;
|
|
I2C2_Rcvbuf_Float = NULL;
|
|
I2C2_Rcvbuf_Int = NULL;
|
|
I2C2_Rcvbuf_String = NULL;
|
|
rcvlen = getinteger(argv[4]);
|
|
if (rcvlen < 1) error("Number out of bounds");
|
|
ptr = findvar(argv[6], V_FIND | V_EMPTY_OK);
|
|
if (g_vartbl[g_VarIndex].type & T_CONST) error("Cannot change a constant");
|
|
if (ptr == NULL) error("Invalid variable");
|
|
if (g_vartbl[g_VarIndex].type & T_NBR) {
|
|
if (g_vartbl[g_VarIndex].dims[1] != 0) error("Invalid variable");
|
|
if (g_vartbl[g_VarIndex].dims[0] <= 0) { // Not an array
|
|
if (rcvlen != 1) error("Invalid variable");
|
|
} else { // An array
|
|
if ((((MMFLOAT * ) ptr - g_vartbl[g_VarIndex].val.fa) + rcvlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase))
|
|
error("Insufficient space in array");
|
|
}
|
|
I2C2_Rcvbuf_Float = (MMFLOAT * ) ptr;
|
|
} else if (g_vartbl[g_VarIndex].type & T_INT) {
|
|
if (g_vartbl[g_VarIndex].dims[1] != 0) error("Invalid variable");
|
|
if (g_vartbl[g_VarIndex].dims[0] <= 0) { // Not an array
|
|
if (rcvlen != 1) error("Invalid variable");
|
|
} else { // An array
|
|
if ((((long long int * ) ptr - g_vartbl[g_VarIndex].val.ia) + rcvlen) > (g_vartbl[g_VarIndex].dims[0] + 1 - g_OptionBase))
|
|
error("Insufficient space in array");
|
|
}
|
|
I2C2_Rcvbuf_Int = (long long int * ) ptr;
|
|
} else if (g_vartbl[g_VarIndex].type & T_STR) {
|
|
if (rcvlen < 1 || rcvlen > 255) error("Number out of bounds");
|
|
if (g_vartbl[g_VarIndex].dims[0] != 0) error("Invalid variable");
|
|
*(char * ) ptr = rcvlen;
|
|
I2C2_Rcvbuf_String = (char * ) ptr + 1;
|
|
} else error("Invalid variable");
|
|
I2C2_Rcvlen = rcvlen;
|
|
|
|
I2C2_Sendlen = 0;
|
|
|
|
char * buff = GetTempMemory(rcvlen > 255 ? rcvlen + 2 : STRINGSIZE);
|
|
i2c2_masterCommand(1, (unsigned char * ) buff);
|
|
}
|
|
|
|
/**************************************************************************************************
|
|
Enable the I2C1 module - master mode
|
|
***************************************************************************************************/
|
|
void i2c_enable(int bps) {
|
|
ExtCfg(I2C0SDApin, EXT_COM_RESERVED, 0);
|
|
ExtCfg(I2C0SCLpin, EXT_COM_RESERVED, 0);
|
|
i2c_init(i2c0, bps * 1000);
|
|
gpio_pull_up(PinDef[I2C0SDApin].GPno);
|
|
gpio_pull_up(PinDef[I2C0SCLpin].GPno);
|
|
I2C_enabled = 1;
|
|
}
|
|
void i2c2_enable(int bps) {
|
|
ExtCfg(I2C1SDApin, EXT_COM_RESERVED, 0);
|
|
ExtCfg(I2C1SCLpin, EXT_COM_RESERVED, 0);
|
|
i2c_init(i2c1, bps * 1000);
|
|
gpio_pull_up(PinDef[I2C1SDApin].GPno);
|
|
gpio_pull_up(PinDef[I2C1SCLpin].GPno);
|
|
I2C2_enabled = 1;
|
|
}
|
|
|
|
/**************************************************************************************************
|
|
Disable the I2C1 module - master mode
|
|
***************************************************************************************************/
|
|
void i2c_disable() {
|
|
if (I2C_Status & I2C_Status_Slave) {
|
|
irq_set_enabled(I2C0_IRQ, false);
|
|
irq_remove_handler(I2C0_IRQ, i2c0_irq_handler);
|
|
i2c_set_slave_mode(i2c0, false, I2C_Slave_Addr);
|
|
i2c0 -> hw -> intr_mask = 0;
|
|
}
|
|
I2C_Status = I2C_Status_Disable;
|
|
I2C_Rcvbuf_String = NULL; // pointer to the master receive buffer
|
|
I2C_Rcvbuf_Float = NULL;
|
|
I2C_Rcvbuf_Int = NULL;
|
|
I2C_Sendlen = 0; // length of the master send buffer
|
|
I2C_Rcvlen = 0; // length of the master receive buffer
|
|
I2C_Addr = 0; // I2C device address
|
|
I2C_Timeout = 0; // master timeout value
|
|
i2c_deinit(i2c0);
|
|
I2C_enabled = 0;
|
|
if (I2C0SDApin != 99) ExtCfg(I2C0SDApin, EXT_NOT_CONFIG, 0);
|
|
if (I2C0SCLpin != 99) ExtCfg(I2C0SCLpin, EXT_NOT_CONFIG, 0);
|
|
}
|
|
void i2c2_disable() {
|
|
if (I2C2_Status & I2C_Status_Slave) {
|
|
irq_set_enabled(I2C1_IRQ, false);
|
|
irq_remove_handler(I2C1_IRQ, i2c1_irq_handler);
|
|
i2c_set_slave_mode(i2c1, false, I2C_Slave_Addr);
|
|
i2c1 -> hw -> intr_mask = 0;
|
|
}
|
|
I2C2_Status = I2C_Status_Disable;
|
|
I2C2_Rcvbuf_String = NULL; // pointer to the master receive buffer
|
|
I2C2_Rcvbuf_Float = NULL;
|
|
I2C2_Rcvbuf_Int = NULL;
|
|
I2C2_Sendlen = 0; // length of the master send buffer
|
|
I2C2_Rcvlen = 0; // length of the master receive buffer
|
|
I2C2_Addr = 0; // I2C device address
|
|
I2C2_Timeout = 0; // master timeout value
|
|
i2c_deinit(i2c1);
|
|
I2C2_enabled = 0;
|
|
if (I2C1SDApin != 99) ExtCfg(I2C1SDApin, EXT_NOT_CONFIG, 0);
|
|
if (I2C1SCLpin != 99) ExtCfg(I2C1SCLpin, EXT_NOT_CONFIG, 0);
|
|
}
|
|
/**************************************************************************************************
|
|
Send and/or Receive data - master mode
|
|
***************************************************************************************************/
|
|
void i2c_masterCommand(int timer, unsigned char * I2C_Rcv_Buffer) {
|
|
// unsigned char start_type,
|
|
unsigned char i2caddr = I2C_Addr;
|
|
if (I2C_Sendlen) {
|
|
int i2cret = i2c_write_timeout_us(i2c0, (uint8_t) i2caddr, (uint8_t * ) I2C_Send_Buffer, I2C_Sendlen, (I2C_Status == I2C_Status_BusHold ? true : false), I2C_Timeout * 1000);
|
|
mmI2Cvalue = 0;
|
|
if (i2cret == PICO_ERROR_GENERIC) mmI2Cvalue = 1;
|
|
if (i2cret == PICO_ERROR_TIMEOUT) mmI2Cvalue = 2;
|
|
}
|
|
if (I2C_Rcvlen) {
|
|
int i2cret = i2c_read_timeout_us(i2c0, (uint8_t) i2caddr, (uint8_t * ) I2C_Rcv_Buffer, I2C_Rcvlen, (I2C_Status == I2C_Status_BusHold ? true : false), I2C_Timeout * 1000);
|
|
mmI2Cvalue = 0;
|
|
if (i2cret == PICO_ERROR_GENERIC) mmI2Cvalue = 1;
|
|
if (i2cret == PICO_ERROR_TIMEOUT) mmI2Cvalue = 2;
|
|
for (int i = 0; i < I2C_Rcvlen; i++) {
|
|
if (I2C_Rcvbuf_String != NULL) {
|
|
* I2C_Rcvbuf_String = I2C_Rcv_Buffer[i];
|
|
I2C_Rcvbuf_String++;
|
|
}
|
|
if (I2C_Rcvbuf_Float != NULL) {
|
|
* I2C_Rcvbuf_Float = I2C_Rcv_Buffer[i];
|
|
I2C_Rcvbuf_Float++;
|
|
}
|
|
if (I2C_Rcvbuf_Int != NULL) {
|
|
* I2C_Rcvbuf_Int = I2C_Rcv_Buffer[i];
|
|
I2C_Rcvbuf_Int++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void i2c2_masterCommand(int timer, unsigned char * I2C2_Rcv_Buffer) {
|
|
// unsigned char start_type,
|
|
unsigned char i2c2addr = I2C2_Addr;
|
|
if (I2C2_Sendlen) {
|
|
int i2cret = i2c_write_timeout_us(i2c1, (uint8_t) i2c2addr, (uint8_t * ) I2C_Send_Buffer, I2C2_Sendlen, (I2C2_Status == I2C_Status_BusHold ? true : false), I2C2_Timeout * 1000);
|
|
mmI2Cvalue = 0;
|
|
if (i2cret == PICO_ERROR_GENERIC) mmI2Cvalue = 1;
|
|
if (i2cret == PICO_ERROR_TIMEOUT) mmI2Cvalue = 2;
|
|
}
|
|
if (I2C2_Rcvlen) {
|
|
int i2cret = i2c_read_timeout_us(i2c1, (uint8_t) i2c2addr, (uint8_t * ) I2C2_Rcv_Buffer, I2C2_Rcvlen, (I2C2_Status == I2C_Status_BusHold ? true : false), I2C2_Timeout * 1000);
|
|
mmI2Cvalue = 0;
|
|
if (i2cret == PICO_ERROR_GENERIC) mmI2Cvalue = 1;
|
|
if (i2cret == PICO_ERROR_TIMEOUT) mmI2Cvalue = 2;
|
|
for (int i = 0; i < I2C2_Rcvlen; i++) {
|
|
if (I2C2_Rcvbuf_String != NULL) {
|
|
* I2C2_Rcvbuf_String = I2C2_Rcv_Buffer[i];
|
|
I2C2_Rcvbuf_String++;
|
|
}
|
|
if (I2C2_Rcvbuf_Float != NULL) {
|
|
* I2C2_Rcvbuf_Float = I2C2_Rcv_Buffer[i];
|
|
I2C2_Rcvbuf_Float++;
|
|
}
|
|
if (I2C2_Rcvbuf_Int != NULL) {
|
|
* I2C2_Rcvbuf_Int = I2C2_Rcv_Buffer[i];
|
|
I2C2_Rcvbuf_Int++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* @endcond */
|
|
|
|
void fun_mmi2c(void) {
|
|
iret = mmI2Cvalue;
|
|
targ = T_INT;
|
|
}
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
void GeneralSend(unsigned int addr, int nbr, char * p) {
|
|
if (I2C0locked) {
|
|
I2C_Sendlen = nbr; // send one byte
|
|
I2C_Rcvlen = 0;
|
|
memcpy(I2C_Send_Buffer, p, nbr);
|
|
I2C_Addr = addr; // address of the device
|
|
i2c_masterCommand(1, NULL);
|
|
} else {
|
|
I2C2_Sendlen = nbr; // send one byte
|
|
I2C2_Rcvlen = 0;
|
|
memcpy(I2C_Send_Buffer, p, nbr);
|
|
I2C2_Addr = addr; // address of the device
|
|
i2c2_masterCommand(1, NULL);
|
|
}
|
|
}
|
|
|
|
void GeneralReceive(unsigned int addr, int nbr, char * p) {
|
|
if (I2C0locked) {
|
|
I2C_Rcvbuf_Float = NULL;
|
|
I2C_Rcvbuf_Int = NULL;
|
|
I2C_Sendlen = 0; // send one byte
|
|
I2C_Rcvlen = nbr;
|
|
I2C_Addr = addr; // address of the device
|
|
i2c_masterCommand(1, (unsigned char * ) p);
|
|
} else {
|
|
I2C2_Rcvbuf_Float = NULL;
|
|
I2C2_Rcvbuf_Int = NULL;
|
|
I2C2_Sendlen = 0; // send one byte
|
|
I2C2_Rcvlen = nbr;
|
|
I2C2_Addr = addr; // address of the device
|
|
i2c2_masterCommand(1, (unsigned char * ) p);
|
|
}
|
|
}
|
|
void WiiSend(int nbr, char * p) {
|
|
unsigned int addr = nunaddr;
|
|
GeneralSend(addr, nbr, p);
|
|
}
|
|
|
|
void WiiReceive(int nbr, char * p) {
|
|
unsigned int addr = nunaddr;
|
|
GeneralReceive(addr, nbr, p);
|
|
}
|
|
|
|
uint8_t readRegister8(unsigned int addr, uint8_t reg) {
|
|
uint8_t buff;
|
|
GeneralSend(addr, 1, (char * ) & reg);
|
|
GeneralReceive(addr, 1, (char * ) & buff);
|
|
return buff;
|
|
}
|
|
uint32_t readRegister32(unsigned int addr, uint8_t reg) {
|
|
uint32_t buff;
|
|
GeneralSend(addr, 1, (char * ) & reg);
|
|
GeneralReceive(addr, 4, (char * ) & buff);
|
|
return buff;
|
|
}
|
|
void WriteRegister8(unsigned int addr, uint8_t reg, uint8_t data) {
|
|
uint8_t buff[2];
|
|
buff[0] = reg;
|
|
buff[1] = data;
|
|
GeneralSend(addr, 2, (char * ) buff);
|
|
}
|
|
void Write8Register16(unsigned int addr, uint16_t reg, uint8_t data) {
|
|
uint8_t buff[3];
|
|
buff[0] = reg >> 8;
|
|
buff[1] = reg & 0xFF;
|
|
buff[2] = data;
|
|
GeneralSend(addr, 3, (char * ) buff);
|
|
}
|
|
uint8_t read8Register16(unsigned int addr, uint16_t reg) {
|
|
uint8_t buff;
|
|
uint8_t rbuff[2];
|
|
rbuff[0] = reg >> 8;
|
|
rbuff[1] = reg & 0xFF;
|
|
if (I2C0locked) I2C_Status = I2C_Status_BusHold;
|
|
else I2C2_Status = I2C_Status_BusHold;
|
|
GeneralSend(addr, 2, (char * ) rbuff);
|
|
if (I2C0locked) I2C_Status = 0;
|
|
else I2C2_Status = 0;
|
|
GeneralReceive(addr, 1, (char * ) & buff);
|
|
return buff;
|
|
}
|
|
|
|
void nunproc(void) {
|
|
static int lastc = 0, lastz = 0;
|
|
nunstruct[5].x = nunbuff[0];
|
|
nunstruct[5].y = nunbuff[1];
|
|
nunstruct[5].ax = nunbuff[2] << 2;
|
|
nunstruct[5].ay = nunbuff[3] << 2;
|
|
nunstruct[5].az = nunbuff[4] << 2;
|
|
nunstruct[5].Z = (~(nunbuff[5] & 1)) & 1;
|
|
nunstruct[5].C = (~((nunbuff[5] & 2) >> 1)) & 1;
|
|
nunstruct[5].ax += ((nunbuff[5] >> 2) & 3);
|
|
nunstruct[5].ay += ((nunbuff[5] >> 4) & 3);
|
|
nunstruct[5].az += ((nunbuff[5] >> 6) & 3);
|
|
if (lastc == 0 && nunstruct[5].C) {
|
|
lastc = 1;
|
|
nunfoundc[5] = 1;
|
|
}
|
|
if (lastz == 0 && nunstruct[5].Z) {
|
|
lastz = 1;
|
|
nunfoundc[5] = 1;
|
|
}
|
|
if (nunstruct[5].C == 0) lastc = 0;
|
|
if (nunstruct[5].Z == 0) lastz = 0;
|
|
}
|
|
|
|
/* @endcond */
|
|
void MIPS16 cmd_Nunchuck(void) {
|
|
unsigned char * tp = NULL;
|
|
uint32_t id = 0;
|
|
if ((tp = checkstring(cmdline, (unsigned char * )
|
|
"OPEN"))) {
|
|
getargs( & tp, 1, (unsigned char * )
|
|
",");
|
|
if (!(I2C0locked || I2C1locked)) error("SYSTEM I2C not configured");
|
|
if (classic1 || nunchuck1) error("Already open");
|
|
memset((void * ) & nunstruct[5].x, 0, sizeof(nunstruct[5]));
|
|
int retry = 5;
|
|
do {
|
|
WiiSend(sizeof(nuninit), (char * ) nuninit);
|
|
uSec(5000);
|
|
} while (mmI2Cvalue && retry--);
|
|
if (mmI2Cvalue) error("Nunchuck not connected");
|
|
WiiSend(sizeof(nuninit2), (char * ) nuninit2);
|
|
if (mmI2Cvalue) error("Nunchuck not connected");
|
|
uSec(5000);
|
|
retry = 5;
|
|
do {
|
|
WiiSend(sizeof(nunid), (char * ) nunid);
|
|
uSec(5000);
|
|
WiiReceive(4, (char * ) & id);
|
|
uSec(5000);
|
|
} while (mmI2Cvalue && retry--);
|
|
if (mmI2Cvalue) error("Device ID not returned");
|
|
nunstruct[5].type = swap32(id);
|
|
if (nunstruct[5].type != 0xA4200000) error("Device connected is not a Nunchuck");
|
|
uSec(5000);
|
|
retry = 5;
|
|
nunbuff[5] = 0;
|
|
if (argc == 1) {
|
|
nunInterruptc[5] = (char * ) GetIntAddress(argv[0]); // get the interrupt location
|
|
InterruptUsed = true;
|
|
}
|
|
nunchuck1 = 1;
|
|
while (nunchuck1 == 1) routinechecks();
|
|
if (nunbuff[5] == 0 || nunbuff[5] == 255) {
|
|
nunchuck1 = 0;
|
|
error("Nunchuck not responding");
|
|
}
|
|
nunproc();
|
|
return;
|
|
} else if ((tp = checkstring(cmdline, (unsigned char * )
|
|
"CLOSE"))) {
|
|
if (!nunchuck1) error("Not open");
|
|
nunchuck1 = 0;
|
|
nunchuckread = false;
|
|
WiiReceive(6, (char * ) nunbuff);
|
|
nunInterruptc[5] = NULL;
|
|
} else error("Syntax");
|
|
}
|
|
|
|
void MIPS16 cmd_Classic(void) {
|
|
unsigned char * tp = NULL;
|
|
uint32_t id = 0;
|
|
if ((tp = checkstring(cmdline, (unsigned char * )
|
|
"OPEN"))) {
|
|
getargs( & tp, 3, (unsigned char * )
|
|
",");
|
|
if (!(I2C0locked || I2C1locked)) error("SYSTEM I2C not configured");
|
|
if (classic1 || nunchuck1) error("Already open");
|
|
memset((void * ) & nunstruct[0].x, 0, sizeof(nunstruct[0]));
|
|
int retry = 5;
|
|
do {
|
|
WiiSend(sizeof(nuninit), (char * ) nuninit);
|
|
uSec(5000);
|
|
} while (mmI2Cvalue && retry--);
|
|
if (mmI2Cvalue) error("Classic not connected");
|
|
WiiSend(sizeof(nuninit2), (char * ) nuninit2);
|
|
if (mmI2Cvalue) error("Classic not connected");
|
|
uSec(5000);
|
|
retry = 5;
|
|
do {
|
|
WiiSend(sizeof(nunid), (char * ) nunid);
|
|
uSec(5000);
|
|
WiiReceive(4, (char * ) & id);
|
|
uSec(5000);
|
|
} while (mmI2Cvalue && retry--);
|
|
if (mmI2Cvalue) error("Device ID not returned");
|
|
nunstruct[0].type = swap32(id);
|
|
if (nunstruct[0].type == 0xA4200000) error("Device connected is a Nunchuck");
|
|
uSec(5000);
|
|
if (argc >= 1) {
|
|
nunInterruptc[0] = (char * ) GetIntAddress(argv[0]); // get the interrupt location
|
|
InterruptUsed = true;
|
|
nunstruct[0].x1 = 0b111111111111111;
|
|
if (argc == 3) nunstruct[0].x1 = getint(argv[2], 0, 0b111111111111111);
|
|
}
|
|
classic1 = 1;
|
|
while (classic1 == 1) routinechecks();
|
|
if (nunbuff[0] == 0 || nunbuff[0] == 255) {
|
|
classic1 = 0;
|
|
error("Classic not responding");
|
|
}
|
|
classicproc();
|
|
return;
|
|
} else if ((tp = checkstring(cmdline, (unsigned char * )
|
|
"CLOSE"))) {
|
|
if (!classic1) error("Not open");
|
|
classic1 = 0;
|
|
classicread = false;
|
|
WiiReceive(6, (char * ) nunbuff);
|
|
nunInterruptc[0] = NULL;
|
|
} else error("Syntax");
|
|
}
|
|
|
|
/*
|
|
* @cond
|
|
* The following section will be excluded from the documentation.
|
|
*/
|
|
|
|
void classicproc(void) {
|
|
// 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
|
|
static unsigned short buttonlast = 0;
|
|
unsigned short inttest = (((nunbuff[4] >> 1) | (nunbuff[5] << 7)) ^ 0b111111111111111) & nunstruct[0].x1;
|
|
nunstruct[0].classic[0] = nunbuff[0];
|
|
nunstruct[0].classic[1] = nunbuff[1];
|
|
nunstruct[0].classic[2] = nunbuff[2];
|
|
nunstruct[0].classic[3] = nunbuff[3];
|
|
nunstruct[0].classic[4] = nunbuff[4];
|
|
nunstruct[0].classic[5] = nunbuff[5];
|
|
if (inttest != buttonlast) {
|
|
nunfoundc[0] = 1;
|
|
}
|
|
buttonlast = inttest;
|
|
nunstruct[0].ax = (nunbuff[0] & 0b111111) << 2;
|
|
nunstruct[0].ay = (nunbuff[1] & 0b111111) << 2;
|
|
nunstruct[0].Z = (((nunbuff[2] & 0b10000000) >> 7) |
|
|
((nunbuff[1] & 0b11000000) >> 5) |
|
|
((nunbuff[0] & 0b11000000) >> 3)) << 3;
|
|
nunstruct[0].C = (nunbuff[2] & 0b11111) << 3;
|
|
nunstruct[0].R = ((nunbuff[3] & 0b00011111)) << 3;
|
|
nunstruct[0].L = (((nunbuff[3] & 0b11100000) >> 5) |
|
|
((nunbuff[2] & 0b01100000) >> 2)) << 3;
|
|
nunstruct[0].x0 = ((nunbuff[4] >> 1) | (nunbuff[5] << 7)) ^ 0b111111111111111;
|
|
}
|
|
|
|
#ifndef PICOMITEVGA
|
|
#define ov7670_address 0x21
|
|
#define top 120
|
|
#define left 160
|
|
uint8_t PCLK = 0;
|
|
uint8_t XCLK = 0;
|
|
uint8_t HREF = 0;
|
|
uint8_t VSYNC = 0;
|
|
uint8_t RESET = 0;
|
|
uint8_t D0 = 0;
|
|
uint8_t XCLKGP = 0;
|
|
uint8_t PCLKGP = 0;
|
|
uint8_t VSYNCGP = 0;
|
|
uint8_t HREFGP = 0;
|
|
//extern volatile int ExtCurrentConfig[];
|
|
void cameraclose(void) {
|
|
if (PCLK) ExtCfg(PCLK, EXT_NOT_CONFIG, 0);
|
|
if (HREF) ExtCfg(HREF, EXT_NOT_CONFIG, 0);
|
|
if (VSYNC) ExtCfg(VSYNC, EXT_NOT_CONFIG, 0);
|
|
if (RESET) ExtCfg(RESET, EXT_NOT_CONFIG, 0);
|
|
if (D0) {
|
|
int startdata = PinDef[D0].GPno;
|
|
for (int i = startdata; i < startdata + 8; i++) {
|
|
ExtCfg(PINMAP[i], EXT_NOT_CONFIG, 0);
|
|
}
|
|
}
|
|
if (XCLK) {
|
|
PWMoff(CameraSlice);
|
|
ExtCfg(XCLK, EXT_NOT_CONFIG, 0);
|
|
}
|
|
CameraSlice = -1;
|
|
CameraChannel = -1;
|
|
PCLK = HREF = VSYNC = D0 = XCLK = 0;
|
|
}
|
|
int readregister(int reg) {
|
|
unsigned char buff[2];
|
|
if (I2C0locked) {
|
|
I2C_Sendlen = 1; // send one byte
|
|
I2C_Rcvlen = 0;
|
|
* I2C_Send_Buffer = reg; // the first register to read
|
|
I2C_Addr = ov7670_address; // address of the device
|
|
i2c_masterCommand(1, NULL);
|
|
} else {
|
|
I2C2_Sendlen = 1; // send one byte
|
|
I2C2_Rcvlen = 0;
|
|
* I2C_Send_Buffer = reg; // the first register to read
|
|
I2C2_Addr = ov7670_address; // address of the device
|
|
i2c2_masterCommand(1, NULL);
|
|
}
|
|
if (mmI2Cvalue) {
|
|
cameraclose();
|
|
error("I2C failure");
|
|
}
|
|
uSec(1000);
|
|
if (I2C0locked) {
|
|
I2C_Rcvbuf_Float = NULL;
|
|
I2C_Rcvbuf_Int = NULL;
|
|
I2C_Rcvlen = 1; // get 7 bytes
|
|
I2C_Sendlen = 0;
|
|
I2C_Addr = ov7670_address; // address of the device
|
|
i2c_masterCommand(1, buff);
|
|
} else {
|
|
I2C2_Rcvbuf_Float = NULL;
|
|
I2C2_Rcvbuf_Int = NULL;
|
|
I2C2_Rcvlen = 1; // get 7 bytes
|
|
I2C2_Sendlen = 0;
|
|
I2C2_Addr = ov7670_address; // address of the device
|
|
i2c2_masterCommand(1, buff);
|
|
}
|
|
uSec(1000);
|
|
return buff[0];
|
|
}
|
|
|
|
void ov7670_set(char a, char b) {
|
|
//send the command
|
|
if (I2C0locked) {
|
|
I2C_Sendlen = 2; // send one byte
|
|
I2C_Rcvlen = 0;
|
|
I2C_Send_Buffer[0] = a; // the first register to read
|
|
I2C_Send_Buffer[1] = b; // the first register to read
|
|
I2C_Addr = ov7670_address; // address of the device
|
|
i2c_masterCommand(1, NULL);
|
|
} else {
|
|
I2C2_Sendlen = 2; // send one byte
|
|
I2C2_Rcvlen = 0;
|
|
I2C_Send_Buffer[0] = a; // the first register to read
|
|
I2C_Send_Buffer[1] = b; // the first register to read
|
|
I2C2_Addr = ov7670_address; // address of the device
|
|
i2c2_masterCommand(1, NULL);
|
|
}
|
|
if (mmI2Cvalue) {
|
|
cameraclose();
|
|
error("I2C failure");
|
|
}
|
|
if (a == REG_COM7 && b == COM7_RESET) {
|
|
uSec(500000);
|
|
return;
|
|
}
|
|
uSec(1000);
|
|
if (readregister(a) != b) error("Camera Config Failure");
|
|
uSec(1000);
|
|
return;
|
|
}
|
|
|
|
void OV7670_test_pattern(OV7670_pattern pattern) {
|
|
// Read current SCALING_XSC and SCALING_YSC register settings,
|
|
// so image scaling settings aren't corrupted.
|
|
uint8_t xsc = readregister(OV7670_REG_SCALING_XSC);
|
|
uint8_t ysc = readregister(OV7670_REG_SCALING_YSC);
|
|
if (pattern & 1) {
|
|
xsc |= 0x80;
|
|
} else {
|
|
xsc &= ~0x80;
|
|
}
|
|
if (pattern & 2) {
|
|
ysc |= 0x80;
|
|
} else {
|
|
ysc &= ~0x80;
|
|
}
|
|
// Write modified results back to SCALING_XSC and SCALING_YSC registers
|
|
ov7670_set(OV7670_REG_SCALING_XSC, xsc);
|
|
ov7670_set(OV7670_REG_SCALING_YSC, ysc);
|
|
}
|
|
|
|
static
|
|
const OV7670_command
|
|
OV7670_yuv[] = {
|
|
// Manual output format, YUV, use full output range
|
|
{
|
|
OV7670_REG_COM7,
|
|
OV7670_COM7_YUV
|
|
},
|
|
{
|
|
OV7670_REG_COM15,
|
|
OV7670_COM15_R00FF
|
|
},
|
|
{
|
|
0xFF,
|
|
0xFF
|
|
}
|
|
},
|
|
OV7670_rgb[] = {
|
|
// Manual output format, RGB, use RGB565 and full 0-255 output range
|
|
{
|
|
OV7670_REG_COM7,
|
|
OV7670_COM7_RGB
|
|
},
|
|
{
|
|
OV7670_REG_RGB444,
|
|
0
|
|
},
|
|
{
|
|
OV7670_REG_COM15,
|
|
OV7670_COM15_RGB565 | OV7670_COM15_R00FF
|
|
},
|
|
{
|
|
0xFF,
|
|
0xFF
|
|
}
|
|
};
|
|
|
|
void OV7670_frame_control(uint8_t size, uint8_t vstart,
|
|
uint16_t hstart, uint8_t edge_offset,
|
|
uint8_t pclk_delay) {
|
|
uint8_t value;
|
|
|
|
// Enable downsampling if sub-VGA, and zoom if 1:16 scale
|
|
value = (size > OV7670_SIZE_DIV1) ? OV7670_COM3_DCWEN : 0;
|
|
if (size == OV7670_SIZE_DIV16)
|
|
value |= OV7670_COM3_SCALEEN;
|
|
ov7670_set(OV7670_REG_COM3, value);
|
|
|
|
// Enable PCLK division if sub-VGA 2,4,8,16 = 0x19,1A,1B,1C
|
|
value = (size > OV7670_SIZE_DIV1) ? (0x18 + size) : 0;
|
|
ov7670_set(OV7670_REG_COM14, value);
|
|
|
|
// Horiz/vert downsample ratio, 1:8 max (H,V are always equal for now)
|
|
value = (size <= OV7670_SIZE_DIV8) ? size : OV7670_SIZE_DIV8;
|
|
ov7670_set(OV7670_REG_SCALING_DCWCTR, value * 0x11);
|
|
|
|
// Pixel clock divider if sub-VGA
|
|
value = (size > OV7670_SIZE_DIV1) ? (0xF0 + size) : 0x08;
|
|
ov7670_set(OV7670_REG_SCALING_PCLK_DIV, value);
|
|
|
|
// Apply 0.5 digital zoom at 1:16 size (others are downsample only)
|
|
value = (size == OV7670_SIZE_DIV16) ? 0x40 : 0x20; // 0.5, 1.0
|
|
// Read current SCALING_XSC and SCALING_YSC register values because
|
|
// test pattern settings are also stored in those registers and we
|
|
// don't want to corrupt anything there.
|
|
uint8_t xsc = readregister(OV7670_REG_SCALING_XSC);
|
|
uint8_t ysc = readregister(OV7670_REG_SCALING_YSC);
|
|
xsc = (xsc & 0x80) | value; // Modify only scaling bits (not test pattern)
|
|
ysc = (ysc & 0x80) | value;
|
|
// Write modified result back to SCALING_XSC and SCALING_YSC
|
|
ov7670_set(OV7670_REG_SCALING_XSC, xsc);
|
|
ov7670_set(OV7670_REG_SCALING_YSC, ysc);
|
|
|
|
// Window size is scattered across multiple registers.
|
|
// Horiz/vert stops can be automatically calc'd from starts.
|
|
uint16_t vstop = vstart + 480;
|
|
uint16_t hstop = (hstart + 640) % 784;
|
|
ov7670_set(OV7670_REG_HSTART, hstart >> 3);
|
|
ov7670_set(OV7670_REG_HSTOP, hstop >> 3);
|
|
ov7670_set(OV7670_REG_HREF,
|
|
(edge_offset << 6) | ((hstop & 0b111) << 3) |
|
|
(hstart & 0b111));
|
|
ov7670_set(OV7670_REG_VSTART, vstart >> 2);
|
|
ov7670_set(OV7670_REG_VSTOP, vstop >> 2);
|
|
ov7670_set(OV7670_REG_VREF,
|
|
((vstop & 0b11) << 2) | (vstart & 0b11));
|
|
|
|
ov7670_set(OV7670_REG_SCALING_PCLK_DELAY, pclk_delay);
|
|
}
|
|
void OV7670_set_size(OV7670_size size) {
|
|
// Array of five window settings, index of each (0-4) aligns with the five
|
|
// OV7670_size enumeration values. If enum changes, list must change!
|
|
static struct {
|
|
uint8_t vstart;
|
|
uint8_t hstart;
|
|
uint8_t edge_offset;
|
|
uint8_t pclk_delay;
|
|
}
|
|
window[] = {
|
|
// Window settings were tediously determined empirically.
|
|
// I hope there's a formula for this, if a do-over is needed.
|
|
{
|
|
9,
|
|
162,
|
|
2,
|
|
2
|
|
}, // SIZE_DIV1 640x480 VGA
|
|
{
|
|
10,
|
|
174,
|
|
4,
|
|
2
|
|
}, // SIZE_DIV2 320x240 QVGA
|
|
{
|
|
11,
|
|
186,
|
|
2,
|
|
2
|
|
}, // SIZE_DIV4 160x120 QQVGA
|
|
{
|
|
12,
|
|
210,
|
|
0,
|
|
2
|
|
}, // SIZE_DIV8 80x60 ...
|
|
{
|
|
15,
|
|
252,
|
|
3,
|
|
2
|
|
}, // SIZE_DIV16 40x30
|
|
};
|
|
|
|
OV7670_frame_control(size, window[size].vstart, window[size].hstart,
|
|
window[size].edge_offset, window[size].pclk_delay);
|
|
}
|
|
#define ST_PCLK gpio_get(PCLKGP)
|
|
#define ST_HREF gpio_get(HREFGP)
|
|
#define ST_VSYNC gpio_get(VSYNCGP)
|
|
void __not_in_flash_func(capture)(char * buff) {
|
|
char * k = buff;
|
|
while (ST_VSYNC) {} /* wait for the old frame to end */
|
|
while (!ST_VSYNC) {} /* wait for a new frame to start */
|
|
//At this point VSync has gone high and the frame is about to start
|
|
while (!ST_HREF) {} // wait for the first line to start
|
|
while (!ST_PCLK) {} // wait for clock to go high /
|
|
while (ST_PCLK) {} // wait for clock to go back low /
|
|
for (int i = 0; i < 160; i++) {
|
|
while (!ST_PCLK) {} // wait for clock to go high /
|
|
* k++ = gpio_get_all64() >> PinDef[D0].GPno;
|
|
while (ST_PCLK) {} // wait for clock to go back low /
|
|
|
|
// second byte/
|
|
while (!ST_PCLK) {} // wait for clock to go high /
|
|
* k++ = gpio_get_all64() >> PinDef[D0].GPno;
|
|
while (ST_PCLK) {} // wait for clock to go back low /
|
|
}
|
|
while (ST_HREF) {} // wait for the first line to end*/
|
|
k = buff;
|
|
for (int j = 0; j < 119; j++) {
|
|
while (!ST_HREF) {} // wait for the first line to end
|
|
for (int i = 0; i < 160; i++) {
|
|
while (!ST_PCLK) {} // wait for clock to go high /
|
|
* k++ = gpio_get_all64() >> PinDef[D0].GPno;
|
|
while (ST_PCLK) {} // wait for clock to go back low /
|
|
|
|
// second byte/
|
|
while (!ST_PCLK) {} // wait for clock to go high /
|
|
* k++ = gpio_get_all64() >> PinDef[D0].GPno;
|
|
while (ST_PCLK) {} // wait for clock to go back low /
|
|
}
|
|
while (ST_HREF) {} // wait for the first line to end
|
|
}
|
|
}
|
|
void saturation(int s) //-2 to 2
|
|
{
|
|
//color matrix values
|
|
ov7670_set(0x4f, 0x80 + 0x20 * s);
|
|
ov7670_set(0x50, 0x80 + 0x20 * s);
|
|
ov7670_set(0x51, 0x00);
|
|
ov7670_set(0x52, 0x22 + (0x11 * s) / 2);
|
|
ov7670_set(0x53, 0x5e + (0x2f * s) / 2);
|
|
ov7670_set(0x54, 0x80 + 0x20 * s);
|
|
ov7670_set(0x58, 0x9e); //matrix signs
|
|
}
|
|
|
|
/* @endcond */
|
|
|
|
void MIPS16 cmd_camera(void) {
|
|
union colourmap {
|
|
char rgbbytes[4];
|
|
unsigned int rgb;
|
|
}
|
|
c;
|
|
unsigned char * tp = NULL;
|
|
if ((tp = checkstring(cmdline, (unsigned char * )
|
|
"OPEN"))) {
|
|
int pin1, pin2, pin3, pin4, pin5, pin6;
|
|
getargs( & tp, 11, (unsigned char * )
|
|
",");
|
|
if (argc != 11) error("Syntax");
|
|
if (!(Option.DISPLAY_TYPE > I2C_PANEL && Option.DISPLAY_TYPE < BufferedPanel)) error("Invalid display type");
|
|
if (!(I2C0locked || I2C1locked)) error("SYSTEM I2C not configured");
|
|
if (XCLK) error("Camera already open");
|
|
unsigned char code;
|
|
//XCLK pin
|
|
if (!(code = codecheck(argv[0]))) argv[0] += 2;
|
|
pin1 = getinteger(argv[0]);
|
|
if (!code) pin1 = codemap(pin1);
|
|
if (IsInvalidPin(pin1)) error("Invalid pin");
|
|
if (ExtCurrentConfig[pin1] != EXT_NOT_CONFIG) error("Pin %/| is in use", pin1, pin1);
|
|
int slice = getslice(pin1);
|
|
if ((PinDef[Option.DISPLAY_BL].slice & 0x7f) == slice) error("Channel in use for backlight");
|
|
if ((PinDef[pin1].slice & 0x7f) == Option.AUDIO_SLICE) error("Channel in use for Audio");
|
|
|
|
//PCLK pin
|
|
if (!(code = codecheck(argv[2]))) argv[2] += 2;
|
|
pin2 = getinteger(argv[2]);
|
|
if (!code) pin2 = codemap(pin2);
|
|
if (IsInvalidPin(pin2)) error("Invalid pin");
|
|
if (ExtCurrentConfig[pin2] != EXT_NOT_CONFIG) error("Pin %/| is in use", pin2, pin2);
|
|
|
|
//HREF pin
|
|
if (!(code = codecheck(argv[4]))) argv[4] += 2;
|
|
pin3 = getinteger(argv[4]);
|
|
if (!code) pin3 = codemap(pin3);
|
|
if (IsInvalidPin(pin3)) error("Invalid pin");
|
|
if (ExtCurrentConfig[pin3] != EXT_NOT_CONFIG) error("Pin %/| is in use", pin3, pin3);
|
|
|
|
//VSYNC pin
|
|
if (!(code = codecheck(argv[6]))) argv[6] += 2;
|
|
pin4 = getinteger(argv[6]);
|
|
if (!code) pin4 = codemap(pin4);
|
|
if (IsInvalidPin(pin4)) error("Invalid pin");
|
|
if (ExtCurrentConfig[pin4] != EXT_NOT_CONFIG) error("Pin %/| is in use", pin4, pin4);
|
|
|
|
//RESET pin
|
|
if (!(code = codecheck(argv[8]))) argv[8] += 2;
|
|
pin5 = getinteger(argv[8]);
|
|
if (!code) pin5 = codemap(pin5);
|
|
if (IsInvalidPin(pin5)) error("Invalid pin");
|
|
if (ExtCurrentConfig[pin5] != EXT_NOT_CONFIG) error("Pin %/| is in use", pin5, pin5);
|
|
|
|
//D0-D7 pins
|
|
if (!(code = codecheck(argv[10]))) argv[10] += 2;
|
|
pin6 = getinteger(argv[10]);
|
|
if (!code) pin6 = codemap(pin6);
|
|
if (IsInvalidPin(pin6)) error("Invalid pin");
|
|
int startdata = PinDef[pin6].GPno;
|
|
for (int i = startdata; i < startdata + 8; i++) {
|
|
if (IsInvalidPin(PINMAP[i])) error("Invalid pin");
|
|
if (ExtCurrentConfig[PINMAP[i]] != EXT_NOT_CONFIG) error("Pin %/| is in use", PINMAP[i], PINMAP[i]);
|
|
}
|
|
XCLK = pin1;
|
|
PCLK = pin2;
|
|
HREF = pin3;
|
|
VSYNC = pin4;
|
|
RESET = pin5;
|
|
D0 = pin6;
|
|
setpwm(pin1, & CameraChannel, & CameraSlice, 12000000.0, 50.0);
|
|
ExtCfg(XCLK, EXT_COM_RESERVED, 0);
|
|
ExtCfg(PCLK, EXT_DIG_IN, 0);
|
|
ExtCfg(PCLK, EXT_COM_RESERVED, 0);
|
|
ExtCfg(HREF, EXT_DIG_IN, 0);
|
|
ExtCfg(HREF, EXT_COM_RESERVED, 0);
|
|
ExtCfg(VSYNC, EXT_DIG_IN, 0);
|
|
ExtCfg(VSYNC, EXT_COM_RESERVED, 0);
|
|
ExtCfg(RESET, EXT_DIG_OUT, 1);
|
|
ExtCfg(RESET, EXT_COM_RESERVED, 0);
|
|
for (int i = startdata; i < startdata + 8; i++) {
|
|
ExtCfg(PINMAP[i], EXT_DIG_IN, 0);
|
|
ExtCfg(PINMAP[i], EXT_COM_RESERVED, 0);
|
|
}
|
|
PCLKGP = PinDef[PCLK].GPno;
|
|
VSYNCGP = PinDef[VSYNC].GPno;
|
|
HREFGP = PinDef[HREF].GPno;
|
|
uSec(1000);
|
|
PinSetBit(pin5, LATCLR);
|
|
uSec(1000);
|
|
PinSetBit(pin5, LATSET);
|
|
uSec(1000);
|
|
if (readregister(REG_PID) != 118) error("Camera not found");
|
|
ov7670_set(REG_COM7, COM7_RESET); // RESET CAMERA
|
|
ov7670_set(REG_COM7, COM7_RESET); // RESET CAMERA
|
|
ov7670_set(REG_RGB444, 0);
|
|
ov7670_set(REG_COM10, 0x02); // 0x02 VSYNC negative (http://nasulica.homelinux.org/?p=959)
|
|
ov7670_set(REG_MVFP, 0x37);
|
|
// ov7670_set( REG_CLKRC, 0x40);
|
|
ov7670_set(REG_COM11, 0x0A);
|
|
ov7670_set(REG_COM7, COM7_RGB);
|
|
ov7670_set(REG_COM1, 0);
|
|
ov7670_set(REG_COM15, COM15_RGB565);
|
|
ov7670_set(REG_COM9, 0x2A);
|
|
ov7670_set(REG_TSLB, 0x04); // 0D = UYVY 04 = YUYV
|
|
ov7670_set(REG_COM13, 0x88);
|
|
ov7670_set(REG_HSTART, 0x13);
|
|
ov7670_set(REG_HSTOP, 0x01);
|
|
ov7670_set(REG_HREF, 0xb6);
|
|
ov7670_set(REG_VSTART, 0x02);
|
|
ov7670_set(REG_VSTOP, 0x7a);
|
|
ov7670_set(REG_VREF, 0x0a);
|
|
ov7670_set(REG_COM5, 0x61);
|
|
ov7670_set(REG_COM6, 0x4b);
|
|
ov7670_set(0x16, 0x02);
|
|
ov7670_set(0x21, 0x02);
|
|
ov7670_set(0x22, 0x91);
|
|
ov7670_set(0x29, 0x07);
|
|
ov7670_set(0x33, 0x0b);
|
|
ov7670_set(0x35, 0x0b);
|
|
ov7670_set(0x37, 0x1d);
|
|
ov7670_set(0x38, 0x71);
|
|
ov7670_set(0x39, 0x2a);
|
|
ov7670_set(REG_COM12, 0x78);
|
|
|
|
ov7670_set(0x4d, 0x40);
|
|
ov7670_set(0x4e, 0x20);
|
|
ov7670_set(REG_GFIX, 0);
|
|
ov7670_set(0x74, 0x10);
|
|
ov7670_set(0x8d, 0x4f);
|
|
ov7670_set(0x8e, 0);
|
|
ov7670_set(0x8f, 0);
|
|
ov7670_set(0x90, 0);
|
|
ov7670_set(0x91, 0);
|
|
ov7670_set(0x96, 0);
|
|
ov7670_set(0x9a, 0);
|
|
|
|
ov7670_set(0xb0, 0x84);
|
|
ov7670_set(0xb1, 0x0c);
|
|
ov7670_set(0xb2, 0x0e);
|
|
ov7670_set(0xb3, 0x82); //
|
|
ov7670_set(0xb8, 0x0a);
|
|
ov7670_set(0x7a, 0x20); //gamma correction
|
|
ov7670_set(0x7b, 0x10);
|
|
ov7670_set(0x7c, 0x1e);
|
|
ov7670_set(0x7d, 0x35);
|
|
ov7670_set(0x7e, 0x5a);
|
|
ov7670_set(0x7f, 0x69);
|
|
ov7670_set(0x80, 0x76);
|
|
ov7670_set(0x81, 0x80);
|
|
ov7670_set(0x82, 0x88);
|
|
ov7670_set(0x83, 0x8f);
|
|
ov7670_set(0x84, 0x96);
|
|
ov7670_set(0x85, 0xa3);
|
|
ov7670_set(0x86, 0xaf);
|
|
ov7670_set(0x87, 0xc4);
|
|
ov7670_set(0x88, 0xd7);
|
|
ov7670_set(0x89, 0xe8);
|
|
// AGC and AEC parameters. Note we start by disabling those features,
|
|
//then turn them only after tweaking the values.
|
|
ov7670_set(0x13, COM8_FASTAEC | COM8_AECSTEP | COM8_BFILT);
|
|
ov7670_set(0x00, 0);
|
|
ov7670_set(0x10, 0);
|
|
ov7670_set(0x0d, 0x40);
|
|
ov7670_set(0x14, 0x18);
|
|
ov7670_set(0xa5, 0x05);
|
|
ov7670_set(0xab, 0x07);
|
|
ov7670_set(0x24, 0x95);
|
|
ov7670_set(0x25, 0x33);
|
|
ov7670_set(0x26, 0xe3);
|
|
ov7670_set(0x9f, 0x78);
|
|
ov7670_set(0xa0, 0x68);
|
|
ov7670_set(0xa1, 0x03);
|
|
ov7670_set(0xa6, 0xd8);
|
|
ov7670_set(0xa7, 0xd8);
|
|
ov7670_set(0xa8, 0xf0);
|
|
ov7670_set(0xa9, 0x90);
|
|
ov7670_set(0xaa, 0x94);
|
|
ov7670_set(0x13, COM8_FASTAEC | COM8_AECSTEP | COM8_BFILT | COM8_AGC | COM8_AEC);
|
|
// Almost all of these are magic "reserved" values. */
|
|
ov7670_set(0x0e, 0x61);
|
|
ov7670_set(0x0f, 0x4b);
|
|
ov7670_set(0x16, 0x02);
|
|
// ov7670_set(0x1e, 0x27);
|
|
ov7670_set(0x21, 0x02);
|
|
ov7670_set(0x22, 0x91);
|
|
ov7670_set(0x29, 0x07);
|
|
ov7670_set(0x33, 0x0b);
|
|
ov7670_set(0x35, 0x0b);
|
|
ov7670_set(0x37, 0x1d);
|
|
ov7670_set(0x38, 0x71);
|
|
ov7670_set(0x39, 0x2a);
|
|
// ov7670_set(0x3c, 0x78);
|
|
ov7670_set(0x4d, 0x40);
|
|
ov7670_set(0x4e, 0x20);
|
|
ov7670_set(0x69, 0);
|
|
// ov7670_set(0x6b, 0x0a);
|
|
ov7670_set(0x74, 0x10);
|
|
ov7670_set(0x8d, 0x4f);
|
|
ov7670_set(0x8e, 0);
|
|
ov7670_set(0x8f, 0);
|
|
ov7670_set(0x90, 0);
|
|
ov7670_set(0x91, 0);
|
|
ov7670_set(0x96, 0);
|
|
ov7670_set(0x9a, 0);
|
|
ov7670_set(0xb0, 0x84);
|
|
ov7670_set(0xb1, 0x0c);
|
|
ov7670_set(0xb2, 0x0e);
|
|
ov7670_set(0xb3, 0x82);
|
|
ov7670_set(0xb8, 0x0a);
|
|
// More reserved magic, some of which tweaks white balance */
|
|
ov7670_set(0x43, 0x0a);
|
|
ov7670_set(0x44, 0xf0);
|
|
ov7670_set(0x45, 0x34);
|
|
ov7670_set(0x46, 0x58);
|
|
ov7670_set(0x47, 0x28);
|
|
ov7670_set(0x48, 0x3a);
|
|
ov7670_set(0x59, 0x88);
|
|
ov7670_set(0x5a, 0x88);
|
|
ov7670_set(0x5b, 0x44);
|
|
ov7670_set(0x5c, 0x67);
|
|
ov7670_set(0x5d, 0x49);
|
|
ov7670_set(0x5e, 0x0e);
|
|
ov7670_set(0x6c, 0x0a);
|
|
ov7670_set(0x6d, 0x55);
|
|
ov7670_set(0x6e, 0x11);
|
|
ov7670_set(0x6f, 0x9f);
|
|
ov7670_set(0x6a, 0x40);
|
|
ov7670_set(0x01, 0x40);
|
|
ov7670_set(0x02, 0x60);
|
|
// COLOR SETTING
|
|
ov7670_set(0x4f, 0x80);
|
|
ov7670_set(0x50, 0x80);
|
|
ov7670_set(0x51, 0x00);
|
|
ov7670_set(0x52, 0x22);
|
|
ov7670_set(0x53, 0x5e);
|
|
ov7670_set(0x54, 0x80);
|
|
ov7670_set(0x56, 0x40);
|
|
ov7670_set(0x58, 0x9e);
|
|
ov7670_set(0x59, 0x88);
|
|
ov7670_set(0x5a, 0x88);
|
|
ov7670_set(0x5b, 0x44);
|
|
ov7670_set(0x5c, 0x67);
|
|
ov7670_set(0x5d, 0x49);
|
|
ov7670_set(0x5e, 0x0e);
|
|
ov7670_set(0x69, 0x00);
|
|
ov7670_set(0x6a, 0x40);
|
|
ov7670_set(0x6b, 0x0a);
|
|
ov7670_set(0x6c, 0x0a);
|
|
ov7670_set(0x6d, 0x55);
|
|
ov7670_set(0x6e, 0x11);
|
|
ov7670_set(0x6f, 0x9f);
|
|
|
|
ov7670_set(0xb0, 0x84);
|
|
ov7670_set(0x13, COM8_FASTAEC | COM8_AECSTEP | COM8_BFILT | COM8_AGC | COM8_AEC | COM8_AWB);
|
|
// Matrix coefficients */
|
|
ov7670_set(0x4f, 0x80);
|
|
ov7670_set(0x50, 0x80);
|
|
ov7670_set(0x51, 0);
|
|
ov7670_set(0x52, 0x22);
|
|
ov7670_set(0x53, 0x5e);
|
|
ov7670_set(0x54, 0x80);
|
|
ov7670_set(0x58, 0x9e);
|
|
|
|
ov7670_set(0x41, 0x08);
|
|
ov7670_set(0x3f, 0);
|
|
ov7670_set(0x75, 0x05);
|
|
ov7670_set(0x76, 0xe1);
|
|
ov7670_set(0x4c, 0);
|
|
ov7670_set(0x77, 0x01);
|
|
ov7670_set(0x3d, 0xc3);
|
|
ov7670_set(0x4b, 0x09);
|
|
ov7670_set(0x41, 0x38);
|
|
ov7670_set(0x56, 0x40);
|
|
|
|
ov7670_set(0x34, 0x11);
|
|
ov7670_set(0x3b, COM11_EXP | COM11_HZAUTO);
|
|
ov7670_set(0xa4, 0x88);
|
|
ov7670_set(0x96, 0);
|
|
ov7670_set(0x97, 0x30);
|
|
ov7670_set(0x98, 0x20);
|
|
ov7670_set(0x99, 0x30);
|
|
ov7670_set(0x9a, 0x84);
|
|
ov7670_set(0x9b, 0x29);
|
|
ov7670_set(0x9c, 0x03);
|
|
ov7670_set(0x9d, 0x4c);
|
|
ov7670_set(0x9e, 0x3f);
|
|
ov7670_set(0x78, 0x04);
|
|
// Extra-weird stuff. Some sort of multiplexor register */
|
|
ov7670_set(0x79, 0x01);
|
|
ov7670_set(0xc8, 0xf0);
|
|
ov7670_set(0x79, 0x0f);
|
|
ov7670_set(0xc8, 0x00);
|
|
ov7670_set(0x79, 0x10);
|
|
ov7670_set(0xc8, 0x7e);
|
|
ov7670_set(0x79, 0x0a);
|
|
ov7670_set(0xc8, 0x80);
|
|
ov7670_set(0x79, 0x0b);
|
|
ov7670_set(0xc8, 0x01);
|
|
ov7670_set(0x79, 0x0c);
|
|
ov7670_set(0xc8, 0x0f);
|
|
ov7670_set(0x79, 0x0d);
|
|
ov7670_set(0xc8, 0x20);
|
|
ov7670_set(0x79, 0x09);
|
|
ov7670_set(0xc8, 0x80);
|
|
ov7670_set(0x79, 0x02);
|
|
ov7670_set(0xc8, 0xc0);
|
|
ov7670_set(0x79, 0x03);
|
|
ov7670_set(0xc8, 0x40);
|
|
ov7670_set(0x79, 0x05);
|
|
ov7670_set(0xc8, 0x30);
|
|
ov7670_set(0x79, 0x26);
|
|
// for (int i = 0; OV7670_init[i].reg <= OV7670_REG_LAST; i++) {
|
|
// ov7670_set(OV7670_init[i].reg, OV7670_init[i].value);
|
|
// }
|
|
saturation(1);
|
|
OV7670_set_size(OV7670_SIZE_DIV4);
|
|
ov7670_set(REG_COM10, 0x02); // 0x02 VSYNC negative (http://nasulica.homelinux.org/?p=959)
|
|
//check the input signals
|
|
uint64_t us = time_us_64() + 1000000;
|
|
while (!ST_PCLK && time_us_64() < us) {} /* wait for clock to go high */
|
|
while (ST_PCLK && time_us_64() < us) {} /* wait for clock to go back low */
|
|
if (time_us_64() > us) error("Timeout on camera PCLK signal");
|
|
while (ST_HREF && time_us_64() < us) {} /* wait for a line to end */
|
|
while (!ST_HREF && time_us_64() < us) {} /* wait for a line to end */
|
|
if (time_us_64() > us) error("Timeout on camera HREF signal");
|
|
while (ST_VSYNC && time_us_64() < us) {} /* wait for the old frame to end */
|
|
while (!ST_VSYNC && time_us_64() < us) {} /* wait for a new frame to start */
|
|
if (time_us_64() > us) error("Timeout on camera VSYNC signal");
|
|
|
|
// OV7670_test_pattern(OV7670_TEST_PATTERN_COLOR_BAR);
|
|
} else if ((tp = checkstring(cmdline, (unsigned char * )
|
|
"TEST"))) {
|
|
getargs( & tp, 1, (unsigned char * )
|
|
",");
|
|
OV7670_test_pattern(getint(argv[0], 0, 3));
|
|
} else if ((tp = checkstring(cmdline, (unsigned char * )
|
|
"REGISTER"))) {
|
|
getargs( & tp, 3, (unsigned char * )
|
|
",");
|
|
if (!XCLK) error("Camera not open");
|
|
int a = getint(argv[0], 0, 255);
|
|
int b = getint(argv[2], 0, 255);
|
|
int c = readregister(a);
|
|
ov7670_set(a, b);
|
|
MMPrintString("Register &H");
|
|
PIntH(a);
|
|
MMPrintString(" was &H");
|
|
PIntH(c);
|
|
MMPrintString(" now &H");
|
|
PIntH(b);
|
|
PRet();
|
|
|
|
} else if ((tp = checkstring(cmdline, (unsigned char * )
|
|
"CHANGE"))) {
|
|
int size = 0;
|
|
unsigned char * cp = NULL;
|
|
int totaldifference = 0, difference;
|
|
if (!XCLK) error("Camera not open");
|
|
getargs( & tp, 9, (unsigned char * )
|
|
",");
|
|
if (!(argc == 3 || argc == 5 || argc == 9)) error("Syntax");
|
|
int xs = 0, ys = 0;
|
|
if (!XCLK) error("Camera not open");
|
|
int scale = 1;
|
|
int64_t * aint;
|
|
size = parseintegerarray(argv[0], & aint, 1, 1, NULL, true);
|
|
cp = (unsigned char * ) aint;
|
|
// get the two variables
|
|
MMFLOAT * outdiff = findvar(argv[2], V_FIND);
|
|
if (!(g_vartbl[g_VarIndex].type & T_NBR)) error("Invalid variable");
|
|
if (size < 160 * 120 / 8) error("Array too small");
|
|
int picout = 0;
|
|
if (argc >= 5) {
|
|
scale = getint(argv[4], 1, HRes / 160);
|
|
picout = 1;
|
|
if (argc == 9) {
|
|
xs = getint(argv[6], 0, HRes - 1);
|
|
ys = getint(argv[8], 0, VRes - 1);
|
|
}
|
|
}
|
|
for (int i = 0; OV7670_yuv[i].reg <= OV7670_REG_LAST; i++) {
|
|
ov7670_set(OV7670_yuv[i].reg, OV7670_yuv[i].value);
|
|
}
|
|
char * buff = GetTempMemory(160 * 120 * 2);
|
|
char * k = buff;
|
|
c.rgb = 0;
|
|
disable_interrupts_pico();
|
|
capture(buff);
|
|
enable_interrupts_pico();
|
|
char * linebuff = NULL;
|
|
if (scale) linebuff = GetTempMemory(160 * 3);
|
|
for (int y = ys; y < 120 * scale + ys; y += scale) {
|
|
int kk = 0;
|
|
for (int x = 0; x < 160; x++) {
|
|
c.rgbbytes[1] = * k++;
|
|
c.rgbbytes[0] = * k++;
|
|
if (c.rgbbytes[1] > * cp) difference = (c.rgbbytes[1] - * cp);
|
|
else difference = ( * cp - c.rgbbytes[1]);
|
|
totaldifference += difference;
|
|
* cp++ = c.rgbbytes[1];
|
|
if (picout) {
|
|
for (int r = 0; r < scale; r++) {
|
|
linebuff[kk++] = difference;
|
|
linebuff[kk++] = difference;
|
|
linebuff[kk++] = difference;
|
|
}
|
|
}
|
|
}
|
|
if (picout) {
|
|
for (int r = 0; r < scale; r++) {
|
|
if (y + r < VRes) {
|
|
int w = 160 * scale;
|
|
if (w > HRes - xs) w = HRes - xs;
|
|
DrawBuffer(xs, y + r, xs + w - 1, y + r, (unsigned char * ) linebuff);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
* outdiff = (MMFLOAT) totaldifference / (160.0 * 120.0 * 255.0) * 100.0;
|
|
} else if ((tp = checkstring(cmdline, (unsigned char * )
|
|
"CAPTURE"))) {
|
|
getargs( & tp, 5, (unsigned char * )
|
|
",");
|
|
int xs = 0, ys = 0;
|
|
if (!XCLK) error("Camera not open");
|
|
int scale = 1;
|
|
if (argc >= 1) {
|
|
scale = getint(argv[0], 1, HRes / 160);
|
|
if (argc == 5) {
|
|
xs = getint(argv[2], 0, HRes - 1);
|
|
ys = getint(argv[4], 0, VRes - 1);
|
|
} else if (argc == 3) error("Syntax");
|
|
}
|
|
for (int i = 0; OV7670_rgb[i].reg <= OV7670_REG_LAST; i++) {
|
|
ov7670_set(OV7670_rgb[i].reg, OV7670_rgb[i].value);
|
|
}
|
|
char * buff = GetTempMemory(160 * 120 * 2);
|
|
c.rgb = 0;
|
|
disable_interrupts_pico();
|
|
capture(buff);
|
|
enable_interrupts_pico();
|
|
char * linebuff = GetTempMemory(160 * 3 * scale);
|
|
char * k = buff;
|
|
for (int y = ys; y < 120 * scale + ys; y += scale) {
|
|
int kk = 0;
|
|
for (int x = 0; x < 160; x++) {
|
|
c.rgbbytes[1] = * k++;
|
|
c.rgbbytes[0] = * k++;
|
|
for (int r = 0; r < scale; r++) {
|
|
linebuff[kk++] = (c.rgbbytes[0] & 0x1F) << 3;
|
|
linebuff[kk++] = (c.rgb & 0x07E0) >> 3;
|
|
linebuff[kk++] = (c.rgbbytes[1] & 0xF8);
|
|
}
|
|
}
|
|
for (int r = 0; r < scale; r++) {
|
|
if (y + r < VRes) {
|
|
int w = 160 * scale;
|
|
if (w > HRes - xs) w = HRes - xs;
|
|
DrawBuffer(xs, y + r, xs + w - 1, y + r, (unsigned char * ) linebuff);
|
|
}
|
|
}
|
|
}
|
|
} else if (checkstring(cmdline, (unsigned char * )
|
|
"CLOSE")) {
|
|
cameraclose();
|
|
} else error("Syntax");
|
|
}
|
|
#endif
|