mirror of
https://github.com/Spritetm/minimacplus.git
synced 2025-02-08 03:30:51 +00:00
Also add esp32 files :/
This commit is contained in:
parent
2525c3af35
commit
3c1e4e5e61
2
components/tme-esp32/component.mk
Normal file
2
components/tme-esp32/component.mk
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#Component makefile
|
||||||
|
|
76
components/tme-esp32/hd.c
Normal file
76
components/tme-esp32/hd.c
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "ncr.h"
|
||||||
|
#include "hd.h"
|
||||||
|
#include "esp_partition.h"
|
||||||
|
#include "esp_heap_alloc_caps.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const esp_partition_t* part;
|
||||||
|
int size;
|
||||||
|
} HdPriv;
|
||||||
|
|
||||||
|
const uint8_t inq_resp[95]={
|
||||||
|
0, //HD
|
||||||
|
0, //0x80 if removable
|
||||||
|
0x49, //Obsolete SCSI standard 1 all the way
|
||||||
|
0, //response version etc
|
||||||
|
31, //extra data
|
||||||
|
0,0, //reserved
|
||||||
|
0, //features
|
||||||
|
'A','P','P','L','E',' ',' ',' ', //vendor id
|
||||||
|
'2','0','S','C',' ',' ',' ',' ', //prod id
|
||||||
|
'1','.','0',' ',' ',' ',' ',' ', //prod rev lvl
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint8_t bouncebuffer[512];
|
||||||
|
|
||||||
|
static int hdScsiCmd(SCSITransferData *data, unsigned int cmd, unsigned int len, unsigned int lba, void *arg) {
|
||||||
|
int ret=0;
|
||||||
|
static uint8_t *bb=NULL;
|
||||||
|
HdPriv *hd=(HdPriv*)arg;
|
||||||
|
if (cmd==0x8 || cmd==0x28) { //read
|
||||||
|
printf("HD: Read %d bytes from LBA %d.\n", len*512, lba);
|
||||||
|
for (int i=0; i<len; i++) {
|
||||||
|
esp_partition_read(hd->part, (lba+i)*512, bouncebuffer, 512);
|
||||||
|
memcpy(&data->data[i*512], bouncebuffer, len*512);
|
||||||
|
}
|
||||||
|
ret=len*512;
|
||||||
|
} else if (cmd==0x12) { //inquiry
|
||||||
|
printf("HD: Inquery\n");
|
||||||
|
memcpy(data->data, inq_resp, sizeof(inq_resp));
|
||||||
|
return 95;
|
||||||
|
} else if (cmd==0x25) { //read capacity
|
||||||
|
int lbacnt=hd->size/512;
|
||||||
|
data->data[0]=(lbacnt>>24);
|
||||||
|
data->data[1]=(lbacnt>>16);
|
||||||
|
data->data[2]=(lbacnt>>8);
|
||||||
|
data->data[3]=(lbacnt>>0);
|
||||||
|
data->data[4]=0;
|
||||||
|
data->data[5]=0;
|
||||||
|
data->data[6]=2; //512
|
||||||
|
data->data[7]=0;
|
||||||
|
ret=8;
|
||||||
|
printf("HD: Read capacity (%d)\n", lbacnt);
|
||||||
|
} else {
|
||||||
|
printf("********** hdScsiCmd: unrecognized command %x\n", cmd);
|
||||||
|
}
|
||||||
|
data->cmd[0]=0; //status
|
||||||
|
data->msg[0]=0;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
SCSIDevice *hdCreate(char *file) {
|
||||||
|
SCSIDevice *ret=malloc(sizeof(SCSIDevice));
|
||||||
|
memset(ret, 0, sizeof(SCSIDevice));
|
||||||
|
HdPriv *hd=malloc(sizeof(HdPriv));
|
||||||
|
memset(hd, 0, sizeof(HdPriv));
|
||||||
|
hd->part=esp_partition_find_first(0x40, 0x2, NULL);
|
||||||
|
if (hd->part==0) printf("Couldn't find HD part!\n");
|
||||||
|
hd->size=hd->part->size;
|
||||||
|
ret->arg=hd;
|
||||||
|
ret->scsiCmd=hdScsiCmd;
|
||||||
|
return ret;
|
||||||
|
}
|
56
components/tme-esp32/main.c
Normal file
56
components/tme-esp32/main.c
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#include "esp_attr.h"
|
||||||
|
|
||||||
|
#include "rom/cache.h"
|
||||||
|
#include "rom/ets_sys.h"
|
||||||
|
#include "rom/spi_flash.h"
|
||||||
|
#include "rom/crc.h"
|
||||||
|
|
||||||
|
#include "soc/soc.h"
|
||||||
|
#include "soc/dport_reg.h"
|
||||||
|
#include "soc/io_mux_reg.h"
|
||||||
|
#include "soc/efuse_reg.h"
|
||||||
|
#include "soc/rtc_cntl_reg.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "freertos/FreeRTOS.h"
|
||||||
|
#include "freertos/task.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "esp_err.h"
|
||||||
|
#include "nvs_flash.h"
|
||||||
|
#include "esp_partition.h"
|
||||||
|
|
||||||
|
#include "emu.h"
|
||||||
|
#include "tmeconfig.h"
|
||||||
|
|
||||||
|
#include "mpu6050.h"
|
||||||
|
|
||||||
|
unsigned char *romdata;
|
||||||
|
|
||||||
|
void emuTask(void *pvParameters)
|
||||||
|
{
|
||||||
|
void *ram=malloc(TME_RAMSIZE);
|
||||||
|
if (ram==NULL) {
|
||||||
|
printf("Couldn't allocate main ram.\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
tmeStartEmu(ram, romdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void app_main()
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
const esp_partition_t* part;
|
||||||
|
spi_flash_mmap_handle_t hrom;
|
||||||
|
esp_err_t err;
|
||||||
|
|
||||||
|
// mpu6050_init();
|
||||||
|
// while(1);
|
||||||
|
|
||||||
|
part=esp_partition_find_first(0x40, 0x1, NULL);
|
||||||
|
if (part==0) printf("Couldn't find bootrom part!\n");
|
||||||
|
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(&emuTask, "emu", 6*1024, NULL, 5, NULL, 0);
|
||||||
|
}
|
||||||
|
|
92
components/tme-esp32/mpu6050.c
Normal file
92
components/tme-esp32/mpu6050.c
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include "driver/i2c.h"
|
||||||
|
|
||||||
|
#define I2C_MASTER_SCL_IO 4 /*!< gpio number for I2C master clock */
|
||||||
|
#define I2C_MASTER_SDA_IO 26 /*!< gpio number for I2C master data */
|
||||||
|
#define I2C_MASTER_NUM I2C_NUM_0 /*!< I2C port number for master dev */
|
||||||
|
#define I2C_MASTER_TX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
|
||||||
|
#define I2C_MASTER_RX_BUF_DISABLE 0 /*!< I2C master do not need buffer */
|
||||||
|
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
|
||||||
|
|
||||||
|
#define WRITEW_BIT 1
|
||||||
|
#define MPU_ADDR (0x68<<1)
|
||||||
|
|
||||||
|
/*
|
||||||
|
esp_err_t i2c_master_read_slave(i2c_port_t i2c_num, uint8_t* data_rd, size_t size)
|
||||||
|
{
|
||||||
|
if (size == 0) {
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||||
|
i2c_master_start(cmd);
|
||||||
|
i2c_master_write_byte(cmd, ( ESP_SLAVE_ADDR << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||||
|
if (size > 1) {
|
||||||
|
i2c_master_read(cmd, data_rd, size - 1, ACK_VAL);
|
||||||
|
}
|
||||||
|
i2c_master_read_byte(cmd, data_rd + size - 1, NACK_VAL);
|
||||||
|
i2c_master_stop(cmd);
|
||||||
|
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 1000 / portTICK_RATE_MS);
|
||||||
|
i2c_cmd_link_delete(cmd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
static esp_err_t setreg(int i2c_num, int reg, int val) {
|
||||||
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||||
|
i2c_master_start(cmd);
|
||||||
|
i2c_master_write_byte(cmd, ( MPU_ADDR | I2C_MASTER_WRITE), true);
|
||||||
|
i2c_master_write_byte(cmd, reg, true);
|
||||||
|
i2c_master_write_byte(cmd, val, true);
|
||||||
|
i2c_master_stop(cmd);
|
||||||
|
esp_err_t ret = i2c_master_cmd_begin(i2c_num, cmd, 100 / portTICK_RATE_MS);
|
||||||
|
i2c_cmd_link_delete(cmd);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getreg(int i2c_num, int reg) {
|
||||||
|
unsigned char byte;
|
||||||
|
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||||
|
i2c_master_start(cmd);
|
||||||
|
i2c_master_write_byte(cmd, ( MPU_ADDR | I2C_MASTER_WRITE), true);
|
||||||
|
i2c_master_write_byte(cmd, reg, true);
|
||||||
|
i2c_master_start(cmd);
|
||||||
|
i2c_master_write_byte(cmd, ( MPU_ADDR | I2C_MASTER_READ), true);
|
||||||
|
i2c_master_read_byte(cmd, &byte, false);
|
||||||
|
i2c_master_stop(cmd);
|
||||||
|
esp_err_t ret=i2c_master_cmd_begin(i2c_num, cmd, 100 / portTICK_RATE_MS);
|
||||||
|
i2c_cmd_link_delete(cmd);
|
||||||
|
if (ret!=ESP_OK) return -1;
|
||||||
|
return byte;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
esp_err_t mpu6050_start(int i2c_num, int samp_div) {
|
||||||
|
int i=getreg(i2c_num, 0x75);
|
||||||
|
printf("Mpu: %x\n", i);
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void mpu6050_poll(int *x, int *y, int *z) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//Actually initializes the i2c port, but atm there's nothing else connected to it... should put this
|
||||||
|
//into some io init routine or something tho'.
|
||||||
|
|
||||||
|
void mpu6050_init() {
|
||||||
|
int i2c_master_port = I2C_MASTER_NUM;
|
||||||
|
i2c_config_t conf;
|
||||||
|
conf.mode = I2C_MODE_MASTER;
|
||||||
|
conf.sda_io_num = I2C_MASTER_SDA_IO;
|
||||||
|
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
|
||||||
|
conf.scl_io_num = I2C_MASTER_SCL_IO;
|
||||||
|
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
|
||||||
|
conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
|
||||||
|
i2c_param_config(i2c_master_port, &conf);
|
||||||
|
i2c_driver_install(i2c_master_port, conf.mode, 1024, 1024, 0);
|
||||||
|
|
||||||
|
mpu6050_start(I2C_MASTER_NUM, 10);
|
||||||
|
}
|
||||||
|
|
2
components/tme-esp32/mpu6050.h
Normal file
2
components/tme-esp32/mpu6050.h
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
void mpu6050_poll(int *x, int *y, int *z);
|
||||||
|
void mpu6050_init();
|
307
components/tme-esp32/spi_lcd.c
Normal file
307
components/tme-esp32/spi_lcd.c
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
/* SPI Master example
|
||||||
|
|
||||||
|
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, this
|
||||||
|
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||||
|
CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
*/
|
||||||
|
#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 PIN_NUM_MISO 25
|
||||||
|
#define PIN_NUM_MOSI 27
|
||||||
|
//#define PIN_NUM_MOSI 23
|
||||||
|
#define PIN_NUM_CLK 19
|
||||||
|
#define PIN_NUM_CS 22
|
||||||
|
|
||||||
|
#define PIN_NUM_DC 21
|
||||||
|
#define PIN_NUM_RST 18
|
||||||
|
#define PIN_NUM_BCKL 5 //backlight enable
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
The ILI9341 needs a bunch of command/argument values to be initialized. They are stored in this struct.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint8_t cmd;
|
||||||
|
uint8_t data[16];
|
||||||
|
uint8_t databytes; //No of data in data; bit 7 = delay after set; 0xFF = end of cmds.
|
||||||
|
} ili_init_cmd_t;
|
||||||
|
|
||||||
|
static const ili_init_cmd_t ili_init_cmds[]={
|
||||||
|
{0xCF, {0x00, 0x83, 0X30}, 3},
|
||||||
|
{0xED, {0x64, 0x03, 0X12, 0X81}, 4},
|
||||||
|
{0xE8, {0x85, 0x01, 0x79}, 3},
|
||||||
|
{0xCB, {0x39, 0x2C, 0x00, 0x34, 0x02}, 5},
|
||||||
|
{0xF7, {0x20}, 1},
|
||||||
|
{0xEA, {0x00, 0x00}, 2},
|
||||||
|
{0xC0, {0x26}, 1},
|
||||||
|
{0xC1, {0x11}, 1},
|
||||||
|
{0xC5, {0x35, 0x3E}, 2},
|
||||||
|
{0xC7, {0xBE}, 1},
|
||||||
|
{0x36, {0x28}, 1},
|
||||||
|
{0x3A, {0x55}, 1},
|
||||||
|
{0xB1, {0x00, 0x1B}, 2},
|
||||||
|
{0xF2, {0x08}, 1},
|
||||||
|
{0x26, {0x01}, 1},
|
||||||
|
{0xE0, {0x1F, 0x1A, 0x18, 0x0A, 0x0F, 0x06, 0x45, 0X87, 0x32, 0x0A, 0x07, 0x02, 0x07, 0x05, 0x00}, 15},
|
||||||
|
{0XE1, {0x00, 0x25, 0x27, 0x05, 0x10, 0x09, 0x3A, 0x78, 0x4D, 0x05, 0x18, 0x0D, 0x38, 0x3A, 0x1F}, 15},
|
||||||
|
{0x2A, {0x00, 0x00, 0x00, 0xEF}, 4},
|
||||||
|
{0x2B, {0x00, 0x00, 0x01, 0x3f}, 4},
|
||||||
|
{0x2C, {0}, 0},
|
||||||
|
{0xB7, {0x07}, 1},
|
||||||
|
{0xB6, {0x0A, 0x82, 0x27, 0x00}, 4},
|
||||||
|
{0x11, {0}, 0x80},
|
||||||
|
{0x29, {0}, 0x80},
|
||||||
|
{0, {0}, 0xff},
|
||||||
|
};
|
||||||
|
|
||||||
|
static spi_device_handle_t spi;
|
||||||
|
|
||||||
|
|
||||||
|
//Send a command to the ILI9341. Uses spi_device_transmit, which waits until the transfer is complete.
|
||||||
|
void ili_cmd(spi_device_handle_t spi, const uint8_t cmd)
|
||||||
|
{
|
||||||
|
esp_err_t ret;
|
||||||
|
spi_transaction_t t;
|
||||||
|
memset(&t, 0, sizeof(t)); //Zero out the transaction
|
||||||
|
t.length=8; //Command is 8 bits
|
||||||
|
t.tx_buffer=&cmd; //The data is the cmd itself
|
||||||
|
t.user=(void*)0; //D/C needs to be set to 0
|
||||||
|
ret=spi_device_transmit(spi, &t); //Transmit!
|
||||||
|
assert(ret==ESP_OK); //Should have had no issues.
|
||||||
|
}
|
||||||
|
|
||||||
|
//Send data to the ILI9341. Uses spi_device_transmit, which waits until the transfer is complete.
|
||||||
|
void ili_data(spi_device_handle_t spi, const uint8_t *data, int len)
|
||||||
|
{
|
||||||
|
esp_err_t ret;
|
||||||
|
spi_transaction_t t;
|
||||||
|
if (len==0) return; //no need to send anything
|
||||||
|
memset(&t, 0, sizeof(t)); //Zero out the transaction
|
||||||
|
t.length=len*8; //Len is in bytes, transaction length is in bits.
|
||||||
|
t.tx_buffer=data; //Data
|
||||||
|
t.user=(void*)1; //D/C needs to be set to 1
|
||||||
|
ret=spi_device_transmit(spi, &t); //Transmit!
|
||||||
|
assert(ret==ESP_OK); //Should have had no issues.
|
||||||
|
}
|
||||||
|
|
||||||
|
//This function is called (in irq context!) just before a transmission starts. It will
|
||||||
|
//set the D/C line to the value indicated in the user field.
|
||||||
|
void ili_spi_pre_transfer_callback(spi_transaction_t *t)
|
||||||
|
{
|
||||||
|
int dc=(int)t->user;
|
||||||
|
gpio_set_level(PIN_NUM_DC, dc);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Initialize the display
|
||||||
|
void ili_init(spi_device_handle_t spi)
|
||||||
|
{
|
||||||
|
int cmd=0;
|
||||||
|
//Initialize non-SPI GPIOs
|
||||||
|
gpio_set_direction(PIN_NUM_DC, GPIO_MODE_OUTPUT);
|
||||||
|
gpio_set_direction(PIN_NUM_RST, GPIO_MODE_OUTPUT);
|
||||||
|
gpio_set_direction(PIN_NUM_BCKL, GPIO_MODE_OUTPUT);
|
||||||
|
|
||||||
|
//Reset the display
|
||||||
|
gpio_set_level(PIN_NUM_RST, 0);
|
||||||
|
vTaskDelay(100 / portTICK_RATE_MS);
|
||||||
|
gpio_set_level(PIN_NUM_RST, 1);
|
||||||
|
vTaskDelay(100 / portTICK_RATE_MS);
|
||||||
|
|
||||||
|
//Send all the commands
|
||||||
|
while (ili_init_cmds[cmd].databytes!=0xff) {
|
||||||
|
ili_cmd(spi, ili_init_cmds[cmd].cmd);
|
||||||
|
ili_data(spi, ili_init_cmds[cmd].data, ili_init_cmds[cmd].databytes&0x1F);
|
||||||
|
if (ili_init_cmds[cmd].databytes&0x80) {
|
||||||
|
vTaskDelay(100 / portTICK_RATE_MS);
|
||||||
|
}
|
||||||
|
cmd++;
|
||||||
|
}
|
||||||
|
|
||||||
|
///Enable backlight
|
||||||
|
gpio_set_level(PIN_NUM_BCKL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void send_header_start(spi_device_handle_t spi, int xpos, int ypos, int w, int h)
|
||||||
|
{
|
||||||
|
esp_err_t ret;
|
||||||
|
int x;
|
||||||
|
//Transaction descriptors. Declared static so they're not allocated on the stack; we need this memory even when this
|
||||||
|
//function is finished because the SPI driver needs access to it even while we're already calculating the next line.
|
||||||
|
static spi_transaction_t trans[5];
|
||||||
|
|
||||||
|
//In theory, it's better to initialize trans and data only once and hang on to the initialized
|
||||||
|
//variables. We allocate them on the stack, so we need to re-init them each call.
|
||||||
|
for (x=0; x<5; x++) {
|
||||||
|
memset(&trans[x], 0, sizeof(spi_transaction_t));
|
||||||
|
if ((x&1)==0) {
|
||||||
|
//Even transfers are commands
|
||||||
|
trans[x].length=8;
|
||||||
|
trans[x].user=(void*)0;
|
||||||
|
} else {
|
||||||
|
//Odd transfers are data
|
||||||
|
trans[x].length=8*4;
|
||||||
|
trans[x].user=(void*)1;
|
||||||
|
}
|
||||||
|
trans[x].flags=SPI_TRANS_USE_TXDATA;
|
||||||
|
}
|
||||||
|
trans[0].tx_data[0]=0x2A; //Column Address Set
|
||||||
|
trans[1].tx_data[0]=xpos>>8; //Start Col High
|
||||||
|
trans[1].tx_data[1]=xpos; //Start Col Low
|
||||||
|
trans[1].tx_data[2]=(xpos+w-1)>>8; //End Col High
|
||||||
|
trans[1].tx_data[3]=(xpos+w-1)&0xff; //End Col Low
|
||||||
|
trans[2].tx_data[0]=0x2B; //Page address set
|
||||||
|
trans[3].tx_data[0]=ypos>>8; //Start page high
|
||||||
|
trans[3].tx_data[1]=ypos&0xff; //start page low
|
||||||
|
trans[3].tx_data[2]=(ypos+h-1)>>8; //end page high
|
||||||
|
trans[3].tx_data[3]=(ypos+h-1)&0xff; //end page low
|
||||||
|
trans[4].tx_data[0]=0x2C; //memory write
|
||||||
|
|
||||||
|
//Queue all transactions.
|
||||||
|
for (x=0; x<5; x++) {
|
||||||
|
ret=spi_device_queue_trans(spi, &trans[x], portMAX_DELAY);
|
||||||
|
assert(ret==ESP_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
//When we are here, the SPI driver is busy (in the background) getting the transactions sent. That happens
|
||||||
|
//mostly using DMA, so the CPU doesn't have much to do here. We're not going to wait for the transaction to
|
||||||
|
//finish because we may as well spend the time calculating the next line. When that is done, we can call
|
||||||
|
//send_line_finish, which will wait for the transfers to be done and check their status.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void send_header_cleanup(spi_device_handle_t spi)
|
||||||
|
{
|
||||||
|
spi_transaction_t *rtrans;
|
||||||
|
esp_err_t ret;
|
||||||
|
//Wait for all 5 transactions to be done and get back the results.
|
||||||
|
for (int x=0; x<5; x++) {
|
||||||
|
ret=spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY);
|
||||||
|
assert(ret==ESP_OK);
|
||||||
|
//We could inspect rtrans now if we received any info back. The LCD is treated as write-only, though.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
volatile static uint8_t *currFbPtr=NULL;
|
||||||
|
SemaphoreHandle_t dispSem = NULL;
|
||||||
|
|
||||||
|
#define NO_SIM_TRANS 5
|
||||||
|
#define MEM_PER_TRANS 1024
|
||||||
|
|
||||||
|
void IRAM_ATTR displayTask(void *arg) {
|
||||||
|
int x, i;
|
||||||
|
int idx=0;
|
||||||
|
int inProgress=0;
|
||||||
|
static uint16_t *dmamem[NO_SIM_TRANS];
|
||||||
|
spi_transaction_t trans[NO_SIM_TRANS];
|
||||||
|
spi_transaction_t *rtrans;
|
||||||
|
|
||||||
|
esp_err_t ret;
|
||||||
|
spi_bus_config_t buscfg={
|
||||||
|
.miso_io_num=PIN_NUM_MISO,
|
||||||
|
.mosi_io_num=PIN_NUM_MOSI,
|
||||||
|
.sclk_io_num=PIN_NUM_CLK,
|
||||||
|
.quadwp_io_num=-1,
|
||||||
|
.quadhd_io_num=-1
|
||||||
|
};
|
||||||
|
spi_device_interface_config_t devcfg={
|
||||||
|
.clock_speed_hz=40000000, //Clock out at 40 MHz. Yes, that's heavily overclocked.
|
||||||
|
.mode=0, //SPI mode 0
|
||||||
|
.spics_io_num=PIN_NUM_CS, //CS pin
|
||||||
|
.queue_size=10, //We want to be able to queue 7 transactions at a time
|
||||||
|
.pre_cb=ili_spi_pre_transfer_callback, //Specify pre-transfer callback to handle D/C line
|
||||||
|
};
|
||||||
|
|
||||||
|
printf("*** Display task starting.\n");
|
||||||
|
|
||||||
|
//Initialize the SPI bus
|
||||||
|
ret=spi_bus_initialize(HSPI_HOST, &buscfg, 1);
|
||||||
|
assert(ret==ESP_OK);
|
||||||
|
//Attach the LCD to the SPI bus
|
||||||
|
ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi);
|
||||||
|
assert(ret==ESP_OK);
|
||||||
|
//Initialize the LCD
|
||||||
|
ili_init(spi);
|
||||||
|
|
||||||
|
for (x=0; x<NO_SIM_TRANS; x++) {
|
||||||
|
dmamem[x]=pvPortMallocCaps(MEM_PER_TRANS*2, MALLOC_CAP_DMA);
|
||||||
|
assert(dmamem[x]);
|
||||||
|
memset(&trans[x], 0, sizeof(spi_transaction_t));
|
||||||
|
trans[x].length=MEM_PER_TRANS*4;
|
||||||
|
trans[x].user=(void*)1;
|
||||||
|
trans[x].tx_buffer=&dmamem[x];
|
||||||
|
}
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
xSemaphoreTake(dispSem, portMAX_DELAY);
|
||||||
|
uint8_t *myData=(uint8_t*)currFbPtr;
|
||||||
|
|
||||||
|
send_header_start(spi, 0, 0, 320, 240);
|
||||||
|
send_header_cleanup(spi);
|
||||||
|
int xpos=0;
|
||||||
|
for (x=0; x<320*240; x+=MEM_PER_TRANS) {
|
||||||
|
i=0;
|
||||||
|
while (i<MEM_PER_TRANS) {
|
||||||
|
for (int j=0x80; j!=0; j>>=1) {
|
||||||
|
dmamem[idx][i++]=(*myData&j)?0:0xffff;
|
||||||
|
}
|
||||||
|
myData++;
|
||||||
|
xpos+=8;
|
||||||
|
if (xpos>=320) {
|
||||||
|
xpos=0;
|
||||||
|
myData+=((512-320)/8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
trans[idx].length=MEM_PER_TRANS*16;
|
||||||
|
trans[idx].user=(void*)1;
|
||||||
|
trans[idx].tx_buffer=dmamem[idx];
|
||||||
|
ret=spi_device_queue_trans(spi, &trans[idx], portMAX_DELAY);
|
||||||
|
assert(ret==ESP_OK);
|
||||||
|
|
||||||
|
idx++;
|
||||||
|
if (idx>=NO_SIM_TRANS) idx=0;
|
||||||
|
|
||||||
|
if (inProgress==NO_SIM_TRANS-1) {
|
||||||
|
ret=spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY);
|
||||||
|
assert(ret==ESP_OK);
|
||||||
|
} else {
|
||||||
|
inProgress++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while(inProgress) {
|
||||||
|
ret=spi_device_get_trans_result(spi, &rtrans, portMAX_DELAY);
|
||||||
|
assert(ret==ESP_OK);
|
||||||
|
inProgress--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void dispDraw(uint8_t *mem) {
|
||||||
|
currFbPtr=mem;
|
||||||
|
xSemaphoreGive(dispSem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void dispInit() {
|
||||||
|
printf("spi_lcd_init()\n");
|
||||||
|
dispSem=xSemaphoreCreateBinary();
|
||||||
|
#if CONFIG_FREERTOS_UNICORE
|
||||||
|
xTaskCreatePinnedToCore(&displayTask, "display", 3000, NULL, 6, NULL, 0);
|
||||||
|
#else
|
||||||
|
xTaskCreatePinnedToCore(&displayTask, "display", 3000, NULL, 6, NULL, 1);
|
||||||
|
#endif
|
||||||
|
}
|
48
components/tme/mouse.c
Normal file
48
components/tme/mouse.c
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#include "mouse.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int dx, dy;
|
||||||
|
int btn;
|
||||||
|
int rpx, rpy;
|
||||||
|
} Mouse;
|
||||||
|
|
||||||
|
static const int quad[4]={0x0, 0x1, 0x3, 0x2};
|
||||||
|
|
||||||
|
Mouse mouse;
|
||||||
|
|
||||||
|
#define MAXCDX 50
|
||||||
|
|
||||||
|
void mouseMove(int dx, int dy, int btn) {
|
||||||
|
mouse.dx+=dx;
|
||||||
|
mouse.dy+=dy;
|
||||||
|
if (mouse.dx>MAXCDX) mouse.dx=MAXCDX;
|
||||||
|
if (mouse.dy>MAXCDX) mouse.dy=MAXCDX;
|
||||||
|
if (mouse.dx<-MAXCDX) mouse.dx=-MAXCDX;
|
||||||
|
if (mouse.dy<-MAXCDX) mouse.dy=-MAXCDX;
|
||||||
|
if (btn) mouse.btn=1; else mouse.btn=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int mouseTick() {
|
||||||
|
int ret=0;
|
||||||
|
if (mouse.dx>0) {
|
||||||
|
mouse.dx--;
|
||||||
|
mouse.rpx--;
|
||||||
|
}
|
||||||
|
if (mouse.dx<0) {
|
||||||
|
mouse.dx++;
|
||||||
|
mouse.rpx++;
|
||||||
|
}
|
||||||
|
if (mouse.dy>0) {
|
||||||
|
mouse.dy--;
|
||||||
|
mouse.rpy++;
|
||||||
|
}
|
||||||
|
if (mouse.dy<0) {
|
||||||
|
mouse.dy++;
|
||||||
|
mouse.rpy--;
|
||||||
|
}
|
||||||
|
ret=quad[mouse.rpx&3];
|
||||||
|
ret|=quad[mouse.rpy&3]<<2;
|
||||||
|
ret|=mouse.btn<<4;
|
||||||
|
// printf("dx %d dy %d ret %x\n", mouse.dx, mouse.dy, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
9
components/tme/mouse.h
Normal file
9
components/tme/mouse.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#define MOUSE_QXA (1<<0)
|
||||||
|
#define MOUSE_QXB (1<<1)
|
||||||
|
#define MOUSE_QYA (1<<2)
|
||||||
|
#define MOUSE_QYB (1<<3)
|
||||||
|
#define MOUSE_BTN (1<<4)
|
||||||
|
|
||||||
|
|
||||||
|
void mouseMove(int dx, int dy, int btn);
|
||||||
|
int mouseTick();
|
133
components/tme/scc.c
Normal file
133
components/tme/scc.c
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "scc.h"
|
||||||
|
#include "m68k.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
THis is an extremely minimal SCC implementation: it only somewhat implements the interrupt mechanism for the
|
||||||
|
DCD pins because that is what is needed for the mouse to work.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
void sccIrq(int ena);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int regptr;
|
||||||
|
int intpending;
|
||||||
|
int intpendingOld;
|
||||||
|
int dcd[2];
|
||||||
|
int cts[2];
|
||||||
|
int wr1[2];
|
||||||
|
int wr15[2];
|
||||||
|
} Scc;
|
||||||
|
|
||||||
|
static Scc scc;
|
||||||
|
|
||||||
|
//WR15 is the External/Status Interrupt Control and has the interrupt enable bits.
|
||||||
|
#define SCC_WR15_BREAK (1<<7)
|
||||||
|
#define SCC_WR15_TXU (1<<6)
|
||||||
|
#define SCC_WR15_CTS (1<<5)
|
||||||
|
#define SCC_WR15_SYNC (1<<4)
|
||||||
|
#define SCC_WR15_DCD (1<<3)
|
||||||
|
#define SCC_WR15_ZCOUNT (1<<1)
|
||||||
|
|
||||||
|
//WR3, when read, gives the Interrupt Pending status.
|
||||||
|
//This is reflected in scc.intpending.
|
||||||
|
#define SCC_WR3_CHB_EXT (1<<0)
|
||||||
|
#define SCC_WR3_CHB_TX (1<<1)
|
||||||
|
#define SCC_WR3_CHB_RX (1<<2)
|
||||||
|
#define SCC_WR3_CHA_EXT (1<<3)
|
||||||
|
#define SCC_WR3_CHA_TX (1<<4)
|
||||||
|
#define SCC_WR3_CHA_RX (1<<5)
|
||||||
|
|
||||||
|
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);
|
||||||
|
sccIrq(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sccSetDcd(int chan, int val) {
|
||||||
|
val=val?1:0;
|
||||||
|
if (scc.dcd[chan]!=val) {
|
||||||
|
if (chan==SCC_CHANA) {
|
||||||
|
scc.intpending|=SCC_WR3_CHA_EXT;
|
||||||
|
} else {
|
||||||
|
scc.intpending|=SCC_WR3_CHB_EXT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((scc.intpending&SCC_WR3_CHA_EXT) && (scc.wr15[SCC_CHANA]&SCC_WR15_DCD)) raiseInt(SCC_CHANA);
|
||||||
|
if ((scc.intpending&SCC_WR3_CHB_EXT) && (scc.wr15[SCC_CHANB]&SCC_WR15_DCD)) raiseInt(SCC_CHANB);
|
||||||
|
if ((scc.intpending&SCC_WR3_CHA_EXT) && (scc.wr15[SCC_CHANA]&SCC_WR15_CTS)) raiseInt(SCC_CHANA);
|
||||||
|
if ((scc.intpending&SCC_WR3_CHB_EXT) && (scc.wr15[SCC_CHANB]&SCC_WR15_CTS)) raiseInt(SCC_CHANB);
|
||||||
|
scc.dcd[chan]=val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sccWrite(unsigned int addr, unsigned int val) {
|
||||||
|
int chan, reg;
|
||||||
|
if (addr & (1<<1)) chan=SCC_CHANA; else chan=SCC_CHANB;
|
||||||
|
if (addr & (1<<2)) {
|
||||||
|
//Data
|
||||||
|
reg=8;
|
||||||
|
} else {
|
||||||
|
//Control
|
||||||
|
reg=scc.regptr;
|
||||||
|
scc.regptr=0;
|
||||||
|
}
|
||||||
|
if (reg==0) {
|
||||||
|
scc.regptr=val&0x7;
|
||||||
|
if ((val&0x38)==0x8) scc.regptr|=8;
|
||||||
|
if ((val&0x38)==0x10) {
|
||||||
|
scc.intpending=0;
|
||||||
|
scc.intpendingOld=0;
|
||||||
|
}
|
||||||
|
} else if (reg==1) {
|
||||||
|
scc.wr1[chan]=val;
|
||||||
|
} else if (reg==15) {
|
||||||
|
scc.wr15[chan]=val;
|
||||||
|
}
|
||||||
|
// printf("SCC: write to addr %x chan %d reg %d val %x\n", addr, chan, reg, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
unsigned int sccRead(unsigned int addr) {
|
||||||
|
int chan, reg, val=0xff;
|
||||||
|
if (addr & (1<<1)) chan=SCC_CHANA; else chan=SCC_CHANB;
|
||||||
|
if (addr & (1<<2)) {
|
||||||
|
//Data
|
||||||
|
reg=8;
|
||||||
|
} else {
|
||||||
|
//Control
|
||||||
|
reg=scc.regptr;
|
||||||
|
scc.regptr=0;
|
||||||
|
}
|
||||||
|
if (reg==0) {
|
||||||
|
val=(1<<2);
|
||||||
|
if (scc.dcd[chan]) val|=(1<<3);
|
||||||
|
if (scc.cts[chan]) val|=(1<<5);
|
||||||
|
} else if (reg==1) {
|
||||||
|
val=scc.wr1[chan];
|
||||||
|
} else if (reg==2 && chan==SCC_CHANB) {
|
||||||
|
//We assume this also does an intack.
|
||||||
|
int rsn=0;
|
||||||
|
if (scc.intpending & SCC_WR3_CHB_EXT) {
|
||||||
|
rsn=1;
|
||||||
|
scc.intpending&=~SCC_WR3_CHB_EXT;
|
||||||
|
}
|
||||||
|
if (scc.intpending & SCC_WR3_CHA_EXT) {
|
||||||
|
rsn=5;
|
||||||
|
scc.intpending&=~SCC_WR3_CHA_EXT;
|
||||||
|
}
|
||||||
|
val=rsn<<1;
|
||||||
|
if (scc.intpending&0x38) raiseInt(SCC_CHANA);
|
||||||
|
if (scc.intpending&0x07) raiseInt(SCC_CHANB);
|
||||||
|
} else if (reg==3) {
|
||||||
|
if (chan==SCC_CHANA) val=scc.intpending; else val=0;
|
||||||
|
} else if (reg==15) {
|
||||||
|
val=scc.wr15[chan];
|
||||||
|
}
|
||||||
|
printf("SCC: read from chan %d reg %d val %x\n", chan, reg, val);
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
8
components/tme/scc.h
Normal file
8
components/tme/scc.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
#define SCC_CHANA 0
|
||||||
|
#define SCC_CHANB 1
|
||||||
|
|
||||||
|
void sccWrite(unsigned int addr, unsigned int val);
|
||||||
|
unsigned int sccRead(unsigned int addr);
|
||||||
|
void sccSetDcd(int chan, int val);
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user