Add mouse support, also add mipi component

This commit is contained in:
Jeroen Domburg 2017-05-30 00:40:17 +08:00
parent dfce5c50be
commit 31c98d83b7
16 changed files with 714 additions and 119 deletions

View File

@ -0,0 +1,2 @@
COMPONENT_ADD_INCLUDEDIRS := .

View File

@ -0,0 +1,91 @@
/*
* Copyright 2001-2010 Georges Menie (www.menie.org)
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the University of California, Berkeley 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS AND CONTRIBUTORS 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 "crc16-ccitt.h"
/* CRC16 implementation acording to CCITT standards */
static const unsigned short crc16tab[256]= {
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
};
static int invert(int d) {
int q=0;
if (d&0x01) q|=0x80;
if (d&0x02) q|=0x40;
if (d&0x04) q|=0x20;
if (d&0x08) q|=0x10;
if (d&0x10) q|=0x08;
if (d&0x20) q|=0x04;
if (d&0x40) q|=0x02;
if (d&0x80) q|=0x01;
return q;
}
unsigned short crc16_ccitt(uint16_t oldcrc, const void *buf, int len)
{
register int counter;
register unsigned short crc = oldcrc;
for( counter = 0; counter < len; counter++) {
char d=*(char *)buf++;
char q=invert(d);
crc = (crc<<8) ^ crc16tab[((crc>>8) ^ q)&0x00FF];
}
return (invert(crc>>8))|(invert(crc&0xff)<<8);
}

View File

@ -0,0 +1,35 @@
/*
* Copyright 2001-2010 Georges Menie (www.menie.org)
* All rights reserved.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of the University of California, Berkeley 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 THE REGENTS AND CONTRIBUTORS ``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 THE REGENTS AND CONTRIBUTORS 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.
*/
#ifndef _CRC16_H_
#define _CRC16_H_
#include <stdint.h>
unsigned short crc16_ccitt(uint16_t oldcrc, const void *buf, int len);
#endif /* _CRC16_H_ */

View File

@ -0,0 +1,52 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
void hexdump (void *addr, int len) {
int i;
unsigned char buff[17];
unsigned char *pc = (unsigned char*)addr;
if (len == 0) {
printf(" ZERO LENGTH\n");
return;
}
if (len < 0) {
printf(" NEGATIVE LENGTH: %i\n",len);
return;
}
// Process every byte in the data.
for (i = 0; i < len; i++) {
// Multiple of 16 means new line (with line offset).
if ((i % 16) == 0) {
// Just don't print ASCII for the zeroth line.
if (i != 0)
printf (" %s\n", buff);
// Output the offset.
printf (" %04x ", i);
}
// Now the hex code for the specific character.
printf (" %02x", pc[i]);
// And store a printable ASCII character for later.
if ((pc[i] < 0x20) || (pc[i] > 0x7e))
buff[i % 16] = '.';
else
buff[i % 16] = pc[i];
buff[(i % 16) + 1] = '\0';
}
// Pad out last line if not exactly 16 characters.
while ((i % 16) != 0) {
printf (" ");
i++;
}
// And print the final ASCII bit.
printf (" %s\n", buff);
}

View File

@ -0,0 +1,2 @@
void hexdump (void *addr, int len);

299
components/mipidisp/mipi.c Normal file
View File

@ -0,0 +1,299 @@
#if 1
/*
Thing to emulate single-lane MIPI using a flipflop and a bunch of resistors.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "driver/spi_common.h"
#include "soc/gpio_struct.h"
#include "soc/spi_struct.h"
#include "soc/spi_reg.h"
#include "driver/gpio.h"
#include "esp_heap_alloc_caps.h"
#include "mipi.h"
#include "hexdump.h"
//IO pins
#define GPIO_D0N_LS 4
#define GPIO_D0P_LS 33
#define GPIO_D0_HS 32
#define GPIO_CLKP_LS 25
#define GPIO_CLKN_LS 27
#define GPIO_FF_NRST 14
#define GPIO_FF_CLK 12
#define GPIO_NRST 5
#define HOST VSPI_HOST
#define IRQSRC ETS_SPI3_DMA_INTR_SOURCE
#define DMACH 2
#define DESCCNT 8
#define SOTEOTWAIT() asm volatile("nop; nop; nop; nop")
//#define SOTEOTWAIT() ets_delay_us(10);
static spi_dev_t *spidev;
static int cur_idle_desc=0;
static lldesc_t idle_dmadesc[3];
static lldesc_t data_dmadesc[DESCCNT];
static SemaphoreHandle_t sem=NULL;
//ToDo: move these to spi_common...
static int spi_freq_for_pre_n(int fapb, int pre, int n) {
return (fapb / (pre * n));
}
/*
* Set the SPI clock to a certain frequency. Returns the effective frequency set, which may be slightly
* different from the requested frequency.
*/
static int spi_set_clock(spi_dev_t *hw, int fapb, int hz, int duty_cycle) {
int pre, n, h, l, eff_clk;
//In hw, n, h and l are 1-64, pre is 1-8K. Value written to register is one lower than used value.
if (hz>((fapb/4)*3)) {
//Using Fapb directly will give us the best result here.
hw->clock.clkcnt_l=0;
hw->clock.clkcnt_h=0;
hw->clock.clkcnt_n=0;
hw->clock.clkdiv_pre=0;
hw->clock.clk_equ_sysclk=1;
eff_clk=fapb;
} else {
//For best duty cycle resolution, we want n to be as close to 32 as possible, but
//we also need a pre/n combo that gets us as close as possible to the intended freq.
//To do this, we bruteforce n and calculate the best pre to go along with that.
//If there's a choice between pre/n combos that give the same result, use the one
//with the higher n.
int bestn=-1;
int bestpre=-1;
int besterr=0;
int errval;
for (n=2; n<=64; n++) { //Start at 2: we need to be able to set h/l so we have at least one high and one low pulse.
//Effectively, this does pre=round((fapb/n)/hz).
pre=((fapb/n)+(hz/2))/hz;
if (pre<=0) pre=1;
if (pre>8192) pre=8192;
errval=abs(spi_freq_for_pre_n(fapb, pre, n)-hz);
if (bestn==-1 || errval<=besterr) {
besterr=errval;
bestn=n;
bestpre=pre;
}
}
n=bestn;
pre=bestpre;
l=n;
//This effectively does round((duty_cycle*n)/256)
h=(duty_cycle*n+127)/256;
if (h<=0) h=1;
hw->clock.clk_equ_sysclk=0;
hw->clock.clkcnt_n=n-1;
hw->clock.clkdiv_pre=pre-1;
hw->clock.clkcnt_h=h-1;
hw->clock.clkcnt_l=l-1;
eff_clk=spi_freq_for_pre_n(fapb, pre, n);
}
return eff_clk;
}
static void spidma_intr(void *arg) {
BaseType_t xHigherPriorityTaskWoken=0;
spidev->dma_int_clr.val=0xFFFFFFFF; //clear all ints
//Data is sent
// ets_printf("int\n");
xSemaphoreGiveFromISR(sem, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken) portYIELD_FROM_ISR();
}
/*
Brings up the clock and data lines to LP11, resyncs the flipflop, restarts the clock and DMA engine.
*/
void mipiResync() {
//Get clock and data transceivers back in idle state
// gpio_set_level(GPIO_D0N_LS, 1);
// SOTEOTWAIT();
// gpio_set_level(GPIO_D0P_LS, 1);
gpio_set_level(GPIO_CLKN_LS, 1);
SOTEOTWAIT();
gpio_set_level(GPIO_CLKP_LS, 1);
//Stop DMA transfer
spidev->dma_conf.dma_tx_stop=1;
while (spidev->ext2.val!=0) ;
//Clear flipflop
gpio_set_level(GPIO_FF_NRST, 0);
ets_delay_us(1);
gpio_set_level(GPIO_FF_NRST, 1);
//Clock is in LP11 now. We should go LP01, LP00 to enable HS receivers
gpio_set_level(GPIO_CLKP_LS, 0);
SOTEOTWAIT();
gpio_set_level(GPIO_CLKN_LS, 0);
cur_idle_desc=0;
idle_dmadesc[0].qe.stqe_next=&idle_dmadesc[0];
//Set SPI to transfer contents of idle dmadesc
spidev->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;
spidev->dma_out_link.start=0;
spidev->dma_in_link.start=0;
spidev->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
spidev->dma_conf.dma_tx_stop=0;
spidev->dma_conf.dma_continue=1;
spidev->dma_conf.out_data_burst_en=1;
spidev->user.usr_mosi_highpart=0;
spidev->dma_out_link.addr=(int)(&idle_dmadesc[0]) & 0xFFFFF;
spidev->dma_out_link.start=1;
spidev->user.usr_mosi=1;
spidev->cmd.usr=1;
//Data pair is in LP11 now. We should go LP01, LP00 to enable HS receivers
// gpio_set_level(GPIO_D0P_LS, 0);
// SOTEOTWAIT();
// gpio_set_level(GPIO_D0N_LS, 0);
}
void mipiInit() {
esp_err_t ret;
bool io_native=false;
spi_bus_config_t buscfg={
.miso_io_num=-1,
.mosi_io_num=GPIO_D0_HS,
.sclk_io_num=GPIO_FF_CLK,
.quadwp_io_num=-1,
.quadhd_io_num=-1,
.max_transfer_sz=4096*3
};
gpio_config_t io_conf={
.intr_type=GPIO_INTR_DISABLE,
.mode=GPIO_MODE_OUTPUT,
.pin_bit_mask=(1<<GPIO_D0N_LS)|(1LL<<GPIO_D0P_LS)|(1LL<<GPIO_D0_HS)|(1<<GPIO_CLKP_LS)|
(1<<GPIO_CLKN_LS)|(1<<GPIO_FF_NRST)|(1<<GPIO_FF_CLK)|(1<<GPIO_NRST),
};
gpio_config(&io_conf);
assert(spicommon_periph_claim(HOST));
ret=spicommon_bus_initialize_io(HOST, &buscfg, DMACH, SPICOMMON_BUSFLAG_MASTER, &io_native);
assert(ret==ESP_OK);
spidev=spicommon_hw_for_host(HOST);
//Set up idle dma desc
uint8_t *idle_mem=pvPortMallocCaps(64, MALLOC_CAP_DMA);
memset(idle_mem, 0, 64);
for (int i=0; i<3; i++) {
idle_dmadesc[i].size=64;
idle_dmadesc[i].length=64;
idle_dmadesc[i].buf=idle_mem;
idle_dmadesc[i].eof=0;
idle_dmadesc[i].sosf=0;
idle_dmadesc[i].owner=1;
idle_dmadesc[i].qe.stqe_next = &idle_dmadesc[i];
}
esp_intr_alloc(IRQSRC, 0, spidma_intr, NULL, NULL);
//Reset DMA
spidev->dma_conf.val|=SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;
spidev->dma_out_link.start=0;
spidev->dma_in_link.start=0;
spidev->dma_conf.val&=~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
//Reset timing
spidev->ctrl2.val=0;
spi_set_clock(spidev, 80000000, 20000000, 128);
//Configure SPI host
spidev->ctrl.rd_bit_order=1; //LSB first
spidev->ctrl.wr_bit_order=1;
spidev->pin.ck_idle_edge=0;
spidev->user.ck_out_edge=0;
spidev->ctrl2.miso_delay_mode=2;
spidev->ctrl.val &= ~(SPI_FREAD_DUAL|SPI_FREAD_QUAD|SPI_FREAD_DIO|SPI_FREAD_QIO);
spidev->user.val &= ~(SPI_FWRITE_DUAL|SPI_FWRITE_QUAD|SPI_FWRITE_DIO|SPI_FWRITE_QIO);
//Disable unneeded ints
spidev->slave.val=0;
spidev->dma_int_ena.val=0;
//Set int on EOF
spidev->dma_int_clr.val=0xFFFFFFFF; //clear all ints
spidev->dma_int_ena.out_eof=1;
// spidev->dma_int_ena.in_suc_eof=1;
//Init GPIO to MIPI idle levels
gpio_set_level(GPIO_D0N_LS, 1);
gpio_set_level(GPIO_D0P_LS, 1);
gpio_set_level(GPIO_CLKN_LS, 1);
gpio_set_level(GPIO_CLKP_LS, 1);
//Reset display
gpio_set_level(GPIO_NRST, 0);
ets_delay_us(200);
gpio_set_level(GPIO_NRST, 1);
//Wait till display lives
vTaskDelay(100/portTICK_RATE_MS);
sem=xSemaphoreCreateBinary();
// xSemaphoreGive(sem);
mipiResync(0);
}
void mipiSendMultiple(uint8_t **data, int *lengths, int count) {
esp_err_t ret;
if (count==0) return; //no need to send anything
assert(data[0][0]==0xB8);
// hexdump(data, count);
//Set up link to new transfer
int next_idle_desc=(cur_idle_desc==0)?1:0;
int last=-1;
for (int i=0; i<count; i++) {
last++;
spicommon_setup_dma_desc_links(&data_dmadesc[last], lengths[i], data[i], false);
//Look for new end
for (; data_dmadesc[last].eof!=1; last++) ;
//Kill eof and make desc point to the next one.
data_dmadesc[last].eof=0;
data_dmadesc[last].qe.stqe_next=&data_dmadesc[last+1];
}
//Make very last data desc go to the runout idle desc
data_dmadesc[last].qe.stqe_next=&idle_dmadesc[2];
//and make the runout go to the end idle desc
idle_dmadesc[2].qe.stqe_next=&idle_dmadesc[next_idle_desc];
idle_dmadesc[2].eof=1;
//Make sure that idle desc keeps spinning
idle_dmadesc[next_idle_desc].qe.stqe_next=&idle_dmadesc[next_idle_desc];
gpio_set_level(GPIO_D0P_LS, 0);
SOTEOTWAIT();
gpio_set_level(GPIO_D0N_LS, 0);
//Break the loop on the current idle descriptor
idle_dmadesc[cur_idle_desc].qe.stqe_next=&data_dmadesc[0];
//Okay, done.
cur_idle_desc=next_idle_desc; //for next time
//Wait until transmission is done
xSemaphoreTake(sem, portMAX_DELAY);
gpio_set_level(GPIO_D0N_LS, 1);
SOTEOTWAIT();
gpio_set_level(GPIO_D0P_LS, 1);
}
void mipiSend(uint8_t *data, int len) {
mipiSendMultiple(&data, &len, 1);
}
#endif

View File

@ -0,0 +1,11 @@
#ifndef MIPI_H
#define MIPI_H
#include <stdint.h>
void mipiSend(uint8_t *data, int count);
void mipiSendMultiple(uint8_t **data, int *lengths, int count);
void mipiInit();
void mipiResync();
#endif

View File

@ -0,0 +1,85 @@
#include <stdio.h>
#include <alloca.h>
#include <stdlib.h>
#include <string.h>
#include <rom/crc.h>
#include "crc16-ccitt.h"
#include "mipi.h"
//Reminder; MIPI is very LSB-first.
typedef struct {
uint8_t sot; //should be 0xB8
uint8_t datatype;
uint16_t wordcount;
uint8_t ecc; //0
uint8_t data[];
//Footer is 2 bytes of checksum.
} __attribute__((packed)) DsiLPHdr;
typedef struct {
uint8_t sot; //should be 0xB8
uint8_t datatype;
uint8_t data[];
//Footer is 1 byte of ECC
} __attribute__((packed)) DsiSPHdr;
// calc XOR parity bit of all '1's in 24 bit value
static char parity (uint32_t val) {
uint32_t i,p;
p=0;
for(i=0; i!=24; i++) {
p^=val;
val>>=1;
}
return (p&1);
}
static uint8_t calc_ecc(uint8_t *buf) {
int ret=0;
uint32_t cmd=(buf[0])+(buf[1]<<8)+(buf[2]<<16);
if(parity(cmd & 0b111100010010110010110111)) ret|=0x01;
if(parity(cmd & 0b111100100101010101011011)) ret|=0x02;
if(parity(cmd & 0b011101001001101001101101)) ret|=0x04;
if(parity(cmd & 0b101110001110001110001110)) ret|=0x08;
if(parity(cmd & 0b110111110000001111110000)) ret|=0x10;
if(parity(cmd & 0b111011111111110000000000)) ret|=0x20;
return ret;
}
static uint16_t mipiword(uint16_t val) {
uint16_t ret;
uint8_t *pret=(uint8_t*)&ret;
pret[0]=(val&0xff);
pret[1]=(val>>8);
return ret;
}
//Warning: CRC isn't tested (my display does not use it)
void mipiDsiSendLong(int type, uint8_t *data, int len) {
DsiLPHdr p;
uint8_t footer[3];
uint8_t *datas[3]={(uint8_t*)&p, data, footer};
int lengths[3]={sizeof(DsiLPHdr), len, sizeof(footer)};
p.sot=0xB8;
p.datatype=type;
p.wordcount=mipiword(len);
p.ecc=calc_ecc((uint8_t*)&p.datatype);
int crc=crc16_ccitt(0xFFFF, data, len);
footer[0]=(crc&0xff);
footer[1]=(crc>>8);
footer[2]=(crc&0x8000)?0:0xff; //need one last level transition at end
mipiSendMultiple(datas, lengths, 3);
}
void mipiDsiSendShort(int type, uint8_t *data, int len) {
DsiSPHdr *p=alloca(sizeof(DsiSPHdr)+2+len);
p->sot=0xB8;
p->datatype=type;
memcpy(p->data, data, len);
p->data[len]=calc_ecc((uint8_t*)&p->datatype);
p->data[len+1]=(p->data[len]&0x80)?0:0xff; //need one last level transition at end
mipiSend((uint8_t*)p, sizeof(DsiSPHdr)+2+len);
}

View File

@ -0,0 +1,2 @@
void mipiDsiSendLong(int type, uint8_t *data, int len);
void mipiDsiSendShort(int type, uint8_t *data, int len);

View File

@ -0,0 +1,105 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "driver/spi_master.h"
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "esp_heap_alloc_caps.h"
#define ADNS_MOSI 19
#define ADNS_MISO 21
#define ADNS_CLK 23
#define ADNS_CS 22
//#define DELAY() asm("nop; nop; nop; nop;nop; nop; nop; nop;nop; nop; nop; nop;nop; nop; nop; nop;")
#define DELAY() ets_delay_us(10);
static void adnsWrite(int adr, int val) {
int data=((adr|0x80)<<8)|val;
gpio_set_level(ADNS_CS, 0);
DELAY();
for (int mask=0x8000; mask!=0; mask>>=1) {
gpio_set_level(ADNS_MOSI, (data&mask)?1:0);
gpio_set_level(ADNS_CLK, 0);
DELAY();
gpio_set_level(ADNS_CLK, 1);
DELAY();
}
gpio_set_level(ADNS_CS, 1);
}
static int adnsRead(int adr) {
int data=((adr&0x7F)<<8);
int out=0;
gpio_set_level(ADNS_CS, 0);
DELAY();
for (int mask=0x8000; mask!=0; mask>>=1) {
gpio_set_level(ADNS_MOSI, (data&mask)?1:0);
gpio_set_level(ADNS_CLK, 0);
DELAY();
gpio_set_level(ADNS_CLK, 1);
if (gpio_get_level(ADNS_MISO)) out|=mask;
DELAY();
}
gpio_set_level(ADNS_CS, 1);
return out&0xff;
}
int adns9500_init() {
volatile int delay;
int t;
gpio_config_t gpioconf[2]={
{
.pin_bit_mask=(1<<ADNS_MOSI)|(1<<ADNS_CS)|(1<<ADNS_CLK),
.mode=GPIO_MODE_OUTPUT,
.pull_up_en=GPIO_PULLUP_DISABLE,
.pull_down_en=GPIO_PULLDOWN_DISABLE,
.intr_type=GPIO_PIN_INTR_DISABLE
},{
.pin_bit_mask=(1<<ADNS_MISO),
.mode=GPIO_MODE_INPUT,
.pull_up_en=GPIO_PULLUP_ENABLE,
.pull_down_en=GPIO_PULLDOWN_DISABLE,
.intr_type=GPIO_PIN_INTR_DISABLE
}
};
gpio_config(&gpioconf[0]);
gpio_config(&gpioconf[1]);
int tout=5;
int r;
do {
adnsWrite(0,0);
adnsWrite(0x3A,0x5a); //Power-Up Reset
vTaskDelay(50/portTICK_RATE_MS);
adnsRead(0x2);
adnsRead(0x3);
adnsRead(0x4);
adnsRead(0x5);
adnsRead(0x6);
r=adnsRead(0);
printf("ADNS: Read %X\n", r);
tout--;
} while (r!=0x33 && tout!=0);
if (tout==0) return 0;
adnsWrite(0x20, 0); //Main laser turn on !!!
return 1;
}
void adns900_get_dxdybtn(int *x, int *y, int *btn) {
int16_t sx, sy;
sx=adnsRead(0x3);
sx|=adnsRead(0x4)<<8;
sy=adnsRead(0x5);
sy|=adnsRead(0x6)<<8;
// printf("Mouse: %d %d\n", sx, sy);
*x=sx;
*y=sy;
*btn=gpio_get_level(ADNS_MISO)?0:1;
}

View File

@ -0,0 +1,3 @@
int adns9500_init();
void adns900_get_dxdybtn(int *x, int *y, int *btn);

View File

@ -21,9 +21,6 @@
#include "emu.h"
#include "tmeconfig.h"
#include "mpu6050.h"
#include "mpumouse.h"
unsigned char *romdata;
void emuTask(void *pvParameters)
@ -36,17 +33,6 @@ void emuTask(void *pvParameters)
tmeStartEmu(ram, romdata);
}
void mouseTask(void *pvParameters)
{
printf("Starting mouse task...\n");
while(!mpu6050_init()) {
printf("Can't init MPU....\n");
vTaskDelay(100);
}
mpuMouseEmu();
}
void app_main()
{
@ -60,7 +46,6 @@ void app_main()
err=esp_partition_mmap(part, 0, 128*1024, SPI_FLASH_MMAP_DATA, (const void**)&romdata, &hrom);
if (err!=ESP_OK) printf("Couldn't map bootrom part!\n");
printf("Starting emu...\n");
// xTaskCreatePinnedToCore(&mouseTask, "mouse", 6*1024, NULL, 6, NULL, 0);
xTaskCreatePinnedToCore(&emuTask, "emu", 8*1024, NULL, 5, NULL, 0);
xTaskCreatePinnedToCore(&emuTask, "emu", 6*1024, NULL, 5, NULL, 0);
}

View File

@ -16,9 +16,8 @@
#include "soc/gpio_struct.h"
#include "driver/gpio.h"
#include "esp_heap_alloc_caps.h"
#include "mpumouse.h"
#include "mouse.h"
#include "adns9500.h"
#include "mipi.h"
#include "mipi_dsi.h"
@ -31,92 +30,7 @@ typedef struct {
} DispPacket;
//Copied from the X163QLN01 appliation note.
DispPacket initPackets[]={
#if 0
{0x39, 0xF0, 5, {0x55, 0x55, 0x55, 0x55, 0x55}},
{0x39, 0xBD, 5, {0x01, 0x01, 0x01, 0x01, 0x01}},
{0x39, 0xBE, 5, {0x01, 0x01, 0x01, 0x01, 0x01}},
{0x39, 0xBF, 5, {0x01, 0x01, 0x01, 0x01, 0x01}},
{0x39, 0xBB, 3, {0x07, 0x07, 0x07}},
{0x39, 0xD0, 1, {0x00}},
{0x39, 0xD1, 3, {0x00, 0x00, 0x00}},
{0x39, 0xD2, 3, {0x00, 0x00, 0x00}},
{0x39, 0xD3, 3, {0x00, 0x00, 0x00}},
{0x39, 0xC7, 1, {0x40}},
{0x39, 0xF0, 5, {0x55, 0x55, 0x55, 0x55, 0x55}},
{0x15, 0xEB, 1, {0x02}},
{0x15, 0xF5, 1, {0x10}},
{0x39, 0xED, 8, {0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48}},
{0x39, 0xC7, 8, {0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}},
{0x39, 0xFE, 2, {0x08, 0x08}},
{0x39, 0xC3, 3, {0xF2, 0xF2, 0xF2}},
{0x39, 0xE9, 3, {0x00, 0x00, 0x00}},
{0x15, 0xCA, 1, {0x04}},
{0x39, 0xF0, 5, {0x55, 0x55, 0x55, 0x55, 0x55}},
{0x39, 0xB0, 3, {0x00, 0x00, 0x00}},
{0x39, 0xB1, 3, {0x05, 0x05, 0x05}},
{0x39, 0xB2, 3, {0x01, 0x01, 0x01}},
{0x39, 0xB4, 3, {0x07, 0x07, 0x07}},
{0x39, 0xB5, 3, {0x03, 0x03, 0x03}},
{0x39, 0xB6, 3, {0x55, 0x55, 0x55}},
{0x39, 0xB7, 3, {0x35, 0x35, 0x35}},
{0x39, 0xB8, 3, {0x23, 0x23, 0x23}},
{0x39, 0xB9, 3, {0x03, 0x03, 0x03}},
{0x39, 0xBA, 3, {0x03, 0x03, 0x03}},
{0x39, 0xBE, 3, {0x32, 0x32, 0x32}},
{0x39, 0xC2, 12, {0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B}},
{0x39, 0xCF, 7, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
{0x15, 0x35, 1, {0x00}},
{0x15, 0x36, 1, {0x00}},
{0x15, 0xC0, 1, {0x28}},
{0x32, 0x00, 1, {0x00}},
{0x15, 0x51, 1, {0x00}},
{0x05, 0x11, 1, {0x00}},
{0x05, 0x29, 1, {0x00}},
#endif
#if 0
{0x39, 0xF0, 5, {0x55, 0x55, 0x55, 0x55, 0x55}},
{0x39, 0xBD, 5, {0x01, 0x01, 0x01, 0x01, 0x01}},
{0x39, 0xBE, 5, {0x01, 0x01, 0x01, 0x01, 0x01}},
{0x39, 0xBF, 5, {0x01, 0x01, 0x01, 0x01, 0x01}},
{0x39, 0xBB, 3, {0x07, 0x07, 0x07}},
{0x39, 0xD0, 1, {0x00}},
{0x39, 0xD1, 3, {0x00, 0x00, 0x00}},
{0x39, 0xD2, 3, {0x00, 0x00, 0x00}},
{0x39, 0xD3, 3, {0x00, 0x00, 0x00}},
{0x39, 0xC7, 1, {0x40}},
{0x39, 0xF0, 5, {0x55, 0x55, 0x55, 0x55, 0x55}},
{0x15, 0xEB, 1, {0x02}},
{0x15, 0xF5, 1, {0x10}},
{0x39, 0xED, 8, {0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48, 0x48}},
{0x39, 0xC7, 8, {0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F}},
{0x39, 0xFE, 2, {0x08, 0x08}},
{0x39, 0xC3, 3, {0xF2, 0xF2, 0xF2}},
{0x39, 0xE9, 3, {0x00, 0x00, 0x00}},
{0x15, 0xCA, 1, {0x04}},
{0x39, 0xF0, 5, {0x55, 0x55, 0x55, 0x55, 0x55}},
{0x39, 0xB0, 3, {0x00, 0x00, 0x00}},
{0x39, 0xB1, 3, {0x05, 0x05, 0x05}},
{0x39, 0xB2, 3, {0x01, 0x01, 0x01}},
{0x39, 0xB4, 3, {0x07, 0x07, 0x07}},
{0x39, 0xB5, 3, {0x03, 0x03, 0x03}},
{0x39, 0xB6, 3, {0x55, 0x55, 0x55}},
{0x39, 0xB7, 3, {0x35, 0x35, 0x35}},
{0x39, 0xB8, 3, {0x23, 0x23, 0x23}},
{0x39, 0xB9, 3, {0x03, 0x03, 0x03}},
{0x39, 0xBA, 3, {0x03, 0x03, 0x03}},
{0x39, 0xBE, 3, {0x32, 0x32, 0x32}},
{0x39, 0xC2, 12, {0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B}},
{0x39, 0xCF, 7, {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
{0x15, 0x35, 1, {0x00}},
{0x15, 0x36, 1, {0x00}},
{0x15, 0xC0, 1, {0x28}},
{0x32, 0x00, 1, {0x00}},
{0x15, 0x51, 1, {0x00}},
{0x05, 0x11, 1, {0x00}},
{0x05, 0x29, 1, {0x00}},
#endif
#if 1
const DispPacket initPackets[]={
{0x39, 0xF0, 5, {0x55, 0xAA, 0x52, 0x08, 0x00}},
{0x39, 0xBD, 5, {0x01, 0x90, 0x14, 0x14, 0x00}},
{0x39, 0xBE, 5, {0x01, 0x90, 0x14, 0x14, 0x01}},
@ -147,7 +61,6 @@ DispPacket initPackets[]={
{0x32, 0, 0, {0}},
{0x05, 0x11, 1, {0x00}}, //exit_sleep_mode
{0x05, 0x29, 1, {0x00}}, //turn display on
#endif
{0x15, 0x3A, 1, {0x55}}, //16-bit mode
// {0x29, 0x2B, 4, {0x00, 0x00, 0x00, 0xEF}},
{0,0,0,{0}}
@ -223,10 +136,12 @@ SemaphoreHandle_t dispSem = NULL;
#define LINESPERBUF 1
void IRAM_ATTR displayTask(void *arg) {
static void initLcd() {
mipiInit();
vTaskDelay(20/portTICK_RATE_MS); //give screen a sec
for (int j=0; j<2; j++) { //Init multiple times; for mysterious reasons it sometimes doesn't catch first time.
for (int i=0; initPackets[i].type!=0; i++) {
mipiResync();
if (initPackets[i].type==0x39 || initPackets[i].type==0x29) {
uint8_t data[17];
data[0]=initPackets[i].addr;
@ -238,11 +153,15 @@ void IRAM_ATTR displayTask(void *arg) {
if (initPackets[i].type==5) vTaskDelay(300/portTICK_RATE_MS);
}
}
printf("Inited.\n");
}
printf("Display inited.\n");
}
void IRAM_ATTR displayTask(void *arg) {
uint8_t *img=malloc((LINESPERBUF*320*2)+1);
assert(img);
while(1) {
int l=0;
mipiResync();
@ -258,10 +177,10 @@ void IRAM_ATTR displayTask(void *arg) {
}
l++;
if (l>=LINESPERBUF || j==319) {
//mipiDsiSendLong(0x39, img, (LINESPERBUF*320*2)+1);
mipiDsiSendLong(0x39, img, (LINESPERBUF*320*2)+1);
img[0]=0x3c;
l=0;
*p=&img[1];
p=&img[1];
}
}
}
@ -273,13 +192,17 @@ void dispDraw(uint8_t *mem) {
int dx, dy, btn;
currFbPtr=mem;
xSemaphoreGive(dispSem);
// mpuMouseGetDxDyBtn(&dx, &dy, &btn);
// mouseMove(dx, dy, btn);
adns900_get_dxdybtn(&dx, &dy, &btn);
mouseMove(dx, dy, btn);
}
void dispInit() {
initLcd();
printf("spi_lcd_init()\n");
int ret=adns9500_init();
if (!ret) printf("No mouse found!\n");
dispSem=xSemaphoreCreateBinary();
#if CONFIG_FREERTOS_UNICORE
xTaskCreatePinnedToCore(&displayTask, "display", 3000, NULL, 5, NULL, 0);

View File

@ -90,7 +90,7 @@ void m68k_write_memory_8(unsigned int address, unsigned int value) {
ncrWrite((address>>4)&0x7, (address>>9)&1, value);
} else if (address >= 0x800000 && address < 0xC00000) {
sccWrite(address, value);
printf("PC %x: Write to %x: %x\n", pc, address, value);
// printf("PC %x: Write to %x: %x\n", pc, address, value);
} else {
printf("PC %x: Write to %x: %x\n", pc, address, value);
}

View File

@ -43,7 +43,7 @@ static Scc scc;
static void raiseInt(int chan) {
if ((scc.wr1[chan]&1) && (scc.intpending&(~scc.intpendingOld))) {
scc.intpendingOld=scc.intpending;
printf("SCC int, pending %x\n", scc.intpending);
// printf("SCC int, pending %x\n", scc.intpending);
sccIrq(1);
}
}
@ -127,7 +127,7 @@ unsigned int sccRead(unsigned int addr) {
} else if (reg==15) {
val=scc.wr15[chan];
}
printf("SCC: read from chan %d reg %d val %x\n", chan, reg, val);
// printf("SCC: read from chan %d reg %d val %x\n", chan, reg, val);
return val;
}

View File

@ -81,8 +81,8 @@ CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
CONFIG_APP_OFFSET=0x10000
CONFIG_OPTIMIZATION_LEVEL_DEBUG=y
# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set
# CONFIG_OPTIMIZATION_LEVEL_DEBUG is not set
CONFIG_OPTIMIZATION_LEVEL_RELEASE=y
#
# Component config
@ -180,7 +180,7 @@ CONFIG_FATFS_MAX_LFN=255
#
# FreeRTOS
#
CONFIG_FREERTOS_UNICORE=y
# CONFIG_FREERTOS_UNICORE is not set
CONFIG_FREERTOS_CORETIMER_0=y
# CONFIG_FREERTOS_CORETIMER_1 is not set
CONFIG_FREERTOS_HZ=100