Initial fw port to r0p7

This commit is contained in:
Wenting Zhang 2024-04-27 21:32:58 -04:00
parent 42c7b40052
commit 11c7a41474
13 changed files with 199 additions and 281 deletions

View file

@ -25,16 +25,15 @@ pico_sdk_init()
add_executable(fw
bitstream.c
button.c
caster.c
edid.c
fpga.c
fusb302.c
fw.c
max17135.c
power.c
ptn3460.c
tcpm_driver.c
tps65185.c
usb_mux.c
usb_pd_driver.c
usb_pd_policy.c

126
fw/button.c Normal file
View file

@ -0,0 +1,126 @@
//
// Copyright 2024 Wenting Zhang <zephray@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#include <stdio.h>
#include "pico/stdlib.h"
#include "button.h"
#define BTN1 6
#define BTN2 5
#define BTNCNT 2
#define SHORT_PRESS_THRESHOLD 20
#define LONG_PRESS_THRESHOLD 500
#define RELEASE_THRESHOLD 20
void button_init() {
gpio_init(BTN1);
gpio_set_dir(BTN1, GPIO_IN);
gpio_pull_up(BTN1);
gpio_init(BTN2);
gpio_set_dir(BTN2, GPIO_IN);
gpio_pull_up(BTN2);
}
// Scan a single key, ID is the key number from 0, gpio is pin number
// Should be called at ~1ms interval
// Return value:
// 0 when nothing pressed
// 1 when short pressed
// 2 when long pressed
static uint32_t button_scan_single(int id, int gpio) {
static int timecntr[BTNCNT] = {0};
static enum {
STATE_IDLE,
STATE_FIRST_PRESSED,
STATE_HOLDING,
STATE_RELEASED
} state[BTNCNT] = {0};
uint32_t retval = 0;
switch (state[id]) {
case STATE_IDLE:
if (gpio_get(gpio) == 0) {
state[id] = STATE_FIRST_PRESSED;
timecntr[id] = 0;
}
break;
case STATE_FIRST_PRESSED:
timecntr[id]++;
if (gpio_get(gpio) == 0) {
// Still pressing
if (timecntr[id] >= SHORT_PRESS_THRESHOLD) {
state[id] = STATE_HOLDING;
timecntr[id] = 0;
}
}
else {
// No longer pressed
state[id] = STATE_IDLE;
}
break;
case STATE_HOLDING:
timecntr[id]++;
if (gpio_get(gpio) == 0) {
// Still holding
if (timecntr[id] == LONG_PRESS_THRESHOLD) {
// Exactly when reaching the threshold, return the key press
// User gets feedback as soon as the threshold is reached
retval = 2;
}
}
else {
// No longer holding
if (timecntr[id] < LONG_PRESS_THRESHOLD) {
// Is a short press, signal
retval = 1;
}
timecntr[id] = 0;
state[id] = STATE_RELEASED;
}
break;
case STATE_RELEASED:
if (gpio_get(gpio) == 0) {
// Pressed, reset time counter
timecntr[id] = 0;
}
else {
// Keep counting time
// Only treat key as released when reaching threshold
timecntr[id]++;
if (timecntr[id] >= RELEASE_THRESHOLD) {
state[id] = STATE_IDLE;
}
}
break;
}
return retval;
}
uint32_t button_scan() {
uint32_t btn1 = button_scan_single(0, BTN1);
uint32_t btn2 = button_scan_single(1, BTN2);
uint32_t retval = (btn1 & 0x3) | ((btn2 & 0x3) << 2);
return retval;
}

View file

@ -1,5 +1,5 @@
//
// Copyright 2022 Wenting Zhang <zephray@outlook.com>
// Copyright 2024 Wenting Zhang <zephray@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -21,6 +21,5 @@
//
#pragma once
void max_init(void);
void max_set_vcom(uint16_t vcom);
void max_enable(bool en);
void button_init();
uint32_t button_scan();

View file

@ -23,10 +23,7 @@
/* BOARD REVISION CONFIGURATION */
// Eariler revisions are not supported
//#define BOARD_REV_R0P5
//#define BOARD_REV_R0P6
// Lite version uses DVI instead of Type-C DP Alt-mode
#define BOARD_REV_RL0P1
#define BOARD_REV_R0P7
/* SCREEN CONFIGURATION */
@ -50,17 +47,12 @@
/* SET BASED ON PREVIOUS DEFINES, DO NOT MODIFY */
#if defined(BOARD_REV_R0P5)
#define POWER_TPS65185
#define INPUT_TYPEC
#elif defined(BOARD_REV_R0P6)
#define POWER_GPIO
// VCOM measurement is not supported
#define INPUT_TYPEC
#elif defined(BOARD_REV_RL0P1)
#if defined(BOARD_REV_R0P7)
#define POWER_GPIO
#define POWER_GPIO_VCOM_MEASURE
#define INPUT_DVI
#define INPUT_ADV7611
#define INPUT_PTN3460
#define HAS_TYPEC
#else
#error "Unknown board revision"
#endif

View file

@ -27,16 +27,17 @@
#include "edid.h"
#include "config.h"
#if defined(INPUT_DVI)
#ifdef BOARD_USE_EDID_EMU
#define EDID_I2C_ADDRESS (0x50)
#define EDID_I2C (i2c0)
#define EDID_I2C_SDA (0)
#define EDID_I2C_SCL (1)
#define EDID_VID_IN_PARAM (0x81) // DVI input
#elif defined(INPUT_TYPEC)
#define EDID_VID_IN_PARAM (0x85) // DisplayPort input
#endif
// 0x81 for DVI, 0x85 for DP
// Always use 0x85 for now, doesn't really matter
#define EDID_VID_IN_PARAM (0x85)
static char edid[129] = {
0x00, // register number, not part of EDID
0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, // fixed header (0-7)
@ -90,7 +91,7 @@ static char edid[129] = {
0x00 // checksum (127)
};
#ifdef INPUT_DVI
#ifdef BOARD_USE_EDID_EMU
static void edid_i2c_slave_handler(i2c_inst_t *i2c, i2c_slave_event_t event) {
static uint8_t addr = 0;
@ -133,7 +134,7 @@ void edid_init() {
checksum = ~checksum + 1;
edid[128] = checksum;
#ifdef INPUT_DVI
#ifdef BOARD_USE_EDID_EMU
// DVI models has DDC I2C connected directly to the RP2040
// EDID ROM emulation is needed

View file

@ -25,10 +25,10 @@
#include "fpga.h"
#include "bitstream.h"
#define FPGA_CS 12
#define FPGA_MOSI 13
#define FPGA_MISO 14
#define FPGA_SCLK 15
#define FPGA_CS 13
#define FPGA_MOSI 15
#define FPGA_MISO 12
#define FPGA_SCLK 14
#define FPGA_PROG 17
#define FPGA_DONE 18
#define FPGA_SUSP 19

101
fw/fw.c
View file

@ -32,6 +32,7 @@
#include "power.h"
#include "fpga.h"
#include "edid.h"
#include "button.h"
#include "caster.h"
int main()
@ -43,10 +44,28 @@ int main()
printf("\n");
printf("Glider\n");
// TODO: Unify both input options
#if defined(INPUT_DVI)
// Initialize I2C for TCPC/PTN3460/ADV7611 use
i2c_init(i2c1, 100*1000);
gpio_set_function(2, GPIO_FUNC_I2C);
gpio_set_function(3, GPIO_FUNC_I2C);
gpio_pull_up(2);
gpio_pull_up(3);
int result = tcpm_init(0);
if (result)
fatal("Failed to initialize TCPC\n");
int cc1, cc2;
tcpc_config[0].drv->get_cc(0, &cc1, &cc2);
printf("CC status %d %d\n", cc1, cc2);
power_init();
edid_init();
ptn3460_init();
pd_init(0);
sleep_ms(50);
power_enable(true);
//sleep_run_from_xosc();
@ -54,14 +73,10 @@ int main()
// https://ghubcoder.github.io/posts/awaking-the-pico/
fpga_init();
button_init();
//sleep_ms(5000);
//caster_init();
gpio_init(2);
gpio_set_dir(2, GPIO_IN);
gpio_pull_up(2);
int mode_max = 6;
int mode = 1;
UPDATE_MODE modes[6] = {
@ -73,54 +88,6 @@ int main()
UM_AUTO_LUT_ERROR_DIFFUSION
};
while (1) {
//
if (gpio_get(2) == 0) {
sleep_ms(20);
if (gpio_get(2) == 0) {
int i = 0;
while (gpio_get(2) == 0) {
i++;
sleep_ms(1);
if (i > 500)
break;
}
if (i > 500) {
// Long press, clear screen
caster_redraw(0,0,1600,1200);
}
else {
// Short press, switch mode
mode++;
if (mode >= mode_max) mode = 0;
caster_setmode(0,0,1600,1200,modes[mode]);
}
while (gpio_get(2) == 0);
}
while (gpio_get(2) == 0);
}
}
#elif defined(INPUT_TYPEC)
int result = tcpm_init(0);
if (result)
fatal("Failed to initialize TCPC\n");
int cc1, cc2;
tcpc_config[0].drv->get_cc(0, &cc1, &cc2);
printf("CC status %d %d\n", cc1, cc2);
gpio_init(10);
gpio_put(10, 0);
gpio_set_dir(10, GPIO_OUT);
power_init();
power_enable(true); // TODO: should be dependent on DP signal valid
fpga_init();
ptn3460_init();
pd_init(0);
sleep_ms(50);
extern int dp_enabled;
bool hpd_sent = false;
bool dp_valid = false;
@ -138,8 +105,30 @@ int main()
dp_valid = ptn3460_is_valid();
printf(dp_valid ? "Input is valid\n" : "Input is invalid\n");
}
// Key press logic
uint32_t keys = button_scan();
if (keys & 0x1) {
// First key short press
}
if (keys & 0x2) {
// First key long press
// Clear screen
caster_redraw(0,0,1600,1200);
}
if (keys & 0x4) {
// Second key short press
}
if (keys & 0x8) {
// Second key long press
// Switch mode
mode++;
if (mode >= mode_max) mode = 0;
caster_setmode(0,0,1600,1200,modes[mode]);
}
sleep_ms(1);
}
#endif
return 0;
}

View file

@ -1,76 +0,0 @@
//
// Copyright 2022 Wenting Zhang <zephray@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "max17135.h"
#define MAX_I2C i2c0
#define MAX_I2C_ADDR 0x48
void max_write(uint8_t reg, uint8_t val) {
uint8_t buf[2];
int result;
buf[0] = reg;
buf[1] = val;
result = i2c_write_blocking(MAX_I2C, MAX_I2C_ADDR, buf, 2, false);
if (result != 2) {
fatal("Failed writing data to MAX");
}
}
uint8_t max_read(uint8_t reg) {
int result;
uint8_t buf[1];
buf[0] = reg;
result = i2c_write_blocking(MAX_I2C, MAX_I2C_ADDR, buf, 1, true);
if (result != 1) {
fatal("Failed writing data to MAX");
}
result = i2c_read_blocking(MAX_I2C, MAX_I2C_ADDR, buf, 1, false);
if (result != 1) {
fatal("Failed reading data from MAX");
}
return buf[0];
}
void max_set_vcom(uint16_t vcom) {
max_write(0x04, (vcom >> 16));
max_write(0x03, vcom & 0xff);
}
void max_enable(bool en) {
// TODO
}
void max_init(void) {
//max_set_vcom(100); // -1V
printf("Product Revision: %08x\n", max_read(0x06));
printf("Product ID: %08x\n", max_read(0x07));
max_write(0x10, 0x80);
max_write(0x09, 0x01); // Startup
for (int i = 0; i < 20; i++) {
sleep_ms(10);
uint8_t val = max_read(0x05);
printf("Status: %08x\n", val);
}
printf("Fault: %08x\n", max_read(0x0a));
}

View file

@ -28,13 +28,13 @@
#include "utils.h"
#include "edid.h"
#ifdef INPUT_TYPEC
#ifdef INPUT_PTN3460
#define PTN3460_I2C_ADDRESS (0x60)
#define PTN3460_I2C (i2c0)
#define PTN3460_HPD_PIN (8)
#define PTN3460_I2C (i2c1)
#define PTN3460_HPD_PIN (7)
#define PTN3460_PDN_PIN (9)
#define PTN3460_VALID_PIN (2)
#define PTN3460_VALID_PIN (4)
void ptn3460_select_edid_emulation(uint8_t id) {
uint8_t buf[2];

View file

@ -21,7 +21,7 @@
//
#pragma once
#ifdef INPUT_TYPEC
#ifdef INPUT_PTN3460
void ptn3460_init(void);
void ptn3460_set_aux_polarity(int reverse);
bool ptn3460_is_valid(void);

View file

@ -29,16 +29,13 @@ const struct tcpc_config_t tcpc_config[CONFIG_USB_PD_PORT_COUNT] = {
{0, FUSB302_I2C_SLAVE_ADDR, &fusb302_tcpm_drv},
};
#define TCPC_I2C i2c0
#define TCPC_I2C i2c1
#define TCPC_I2C_SDA 0
#define TCPC_I2C_SCL 1
void tcpc_i2c_init(void) {
i2c_init(TCPC_I2C, 100*1000);
gpio_set_function(TCPC_I2C_SDA, GPIO_FUNC_I2C);
gpio_set_function(TCPC_I2C_SCL, GPIO_FUNC_I2C);
gpio_pull_up(TCPC_I2C_SDA);
gpio_pull_up(TCPC_I2C_SCL);
// Should be initialized at board level init to avoid dependencies between
// drivers that need I2C
}
/* I2C wrapper functions - get I2C port / slave addr from config struct. */

View file

@ -1,83 +0,0 @@
//
// Copyright 2022 Wenting Zhang <zephray@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "tps65185.h"
#define TPS_I2C i2c0
#define TPS_I2C_ADDR 0x68
//#define TPS_I2C_ADDR 0x34
#define TPS_EN_PIN 21
void tps_write(uint8_t reg, uint8_t val) {
uint8_t buf[2];
int result;
buf[0] = reg;
buf[1] = val;
result = i2c_write_blocking(TPS_I2C, TPS_I2C_ADDR, buf, 2, false);
if (result != 2) {
fatal("Failed writing data to TPS");
}
}
uint8_t tps_read(uint8_t reg) {
int result;
uint8_t buf[1];
buf[0] = reg;
result = i2c_write_blocking(TPS_I2C, TPS_I2C_ADDR, buf, 1, true);
if (result != 1) {
fatal("Failed writing data to TPS");
}
result = i2c_read_blocking(TPS_I2C, TPS_I2C_ADDR, buf, 1, false);
if (result != 1) {
fatal("Failed reading data from TPS");
}
return buf[0];
}
void tps_set_vcom(uint16_t vcom) {
tps_write(0x04, (vcom >> 16));
tps_write(0x03, vcom & 0xff);
}
void tps_enable(bool en) {
gpio_put(TPS_EN_PIN, en);
}
void tps_init(void) {
gpio_init(TPS_EN_PIN);
gpio_put(TPS_EN_PIN, 1);
gpio_set_dir(TPS_EN_PIN, GPIO_OUT);
for (int i = 0; i < 100; i++) {
sleep_ms(5);
uint8_t val = tps_read(0x0f);
printf("Val: %08x\n", val);
}
sleep_ms(1000);
tps_set_vcom(212); // -1V
printf("VADJ: %08x\n", tps_read(0x02));
printf("UPSEQ0: %08x\n", tps_read(0x09));
printf("UPSEQ1: %08x\n", tps_read(0x0a));
printf("INT1: %08x\n", tps_read(0x07));
printf("INT2: %08x\n", tps_read(0x08));
}

View file

@ -1,26 +0,0 @@
//
// Copyright 2022 Wenting Zhang <zephray@outlook.com>
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
#pragma once
void tps_init(void);
void tps_enable(bool en);
void tps_set_vcom(uint16_t vcom);