temperature sensor: stuff is working, except for the actual temperature readout

This commit is contained in:
Triss 2021-06-21 16:22:01 +02:00
parent 0c90074dc2
commit b76f1ffdc6
10 changed files with 377 additions and 15 deletions

View File

@ -61,12 +61,14 @@ target_sources(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/cdc_uart.c
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/i2c_tinyusb.c
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/spi_serprog.c
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/tempsensor.c
${CMAKE_CURRENT_SOURCE_DIR}/bsp/${FAMILY}/unique.c
${CMAKE_CURRENT_SOURCE_DIR}/src/cdc_serprog.c
${CMAKE_CURRENT_SOURCE_DIR}/src/vnd_i2ctinyusb.c
${CMAKE_CURRENT_SOURCE_DIR}/src/main.c
${CMAKE_CURRENT_SOURCE_DIR}/src/rtconf.c
${CMAKE_CURRENT_SOURCE_DIR}/src/usb_descriptors.c
${CMAKE_CURRENT_SOURCE_DIR}/src/tempsensor.c
)
if(USE_USBCDC_FOR_STDIO)
target_sources(${PROJECT} PUBLIC
@ -82,9 +84,12 @@ target_include_directories(${PROJECT} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/bsp/default/
)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
if(FAMILY STREQUAL "rp2040")
target_link_libraries(${PROJECT} pico_stdlib pico_unique_id hardware_spi
pico_fix_rp2040_usb_device_enumeration hardware_i2c
pico_fix_rp2040_usb_device_enumeration hardware_i2c hardware_adc
tinyusb_device tinyusb_board tinyusb_additions)
if(USE_USBCDC_FOR_STDIO)

View File

@ -181,7 +181,7 @@ __STATIC_INLINE uint8_t DAP_GetProductString (char *str) {
\return String length.
*/
__STATIC_INLINE uint8_t DAP_GetSerNumString (char *str) {
return get_unique_id_u8(str);
return get_unique_id_u8((uint8_t*)str);
}
///@}

View File

@ -6,6 +6,7 @@
#define DBOARD_HAS_CMSISDAP
#define DBOARD_HAS_SERPROG
#define DBOARD_HAS_I2C
#define DBOARD_HAS_TEMPSENSOR
enum {
HID_N_CMSISDAP = 0,

36
bsp/rp2040/tempsensor.c Normal file
View File

@ -0,0 +1,36 @@
#include <hardware/adc.h>
#include "tempsensor.h"
#define T_SLOPE (-0.001721f)
#define T_BIAS (0.706f)
#define V_MAX (3.3f)
#define D_RANGE (4096)
#define T_OFF (27)
// convert float to x.4 fixed format
#define float2fix(x) (int)((x)*(1<<4))
// convert x.4 fixed to 8.4 fixed
__attribute__((__const__))
inline static int16_t trunc_8fix4(int fix) {
if (fix > 4095) fix = 4095;
if (fix < -4096) fix = -4096;
return fix;
}
void tempsense_dev_init(void) {
adc_init();
adc_set_temp_sensor_enabled(true);
}
// 8.4
int16_t tempsense_dev_get_temp(void) {
adc_select_input(4); // select temp sensor
uint16_t result = adc_read();
int temperature = float2fix(T_OFF - T_BIAS / T_SLOPE)
+ (int)result * float2fix(V_MAX / (D_RANGE * T_SLOPE));
return trunc_8fix4(temperature);
}

View File

@ -3,13 +3,27 @@
import argparse, serial, struct
from typing import *
def auto_int(x):
return int(x, 0)
class RTOpt(NamedTuple):
type: bool
optid: int
desc: str
supportmap = {
1: "CMSIS-DAP",
2: "UART",
4: "I2C-Tiny-USB",
8: "Temperature sensor",
0x80: "stdio USB-CDC debug interface"
}
option_table = {
'ctsrts': RTOpt(bool, 1, "Enable or disable CTS/RTS flow control (--ctsrts [true|false])")
'ctsrts': RTOpt(bool, 1, "Enable or disable CTS/RTS flow control (--ctsrts [true|false])"),
'i2ctemp': RTOpt(auto_int, 2, "Control the builtin I2C temperature controller: get (0), disable (-1/0xff) or set/enable (other) the current status and I2C bus address"),
'support': RTOpt(str, 0xff, "Get list of supported/implemented functionality"),
}
S_ACK = b'\x06'
@ -25,6 +39,10 @@ S_CMD_MAGIC_SETTINGS = b'\x53'
def val2byte(t, v) -> int:
if t == bool:
return 1 if v else 0
if t == int or t == auto_int:
return 0xff if v < 0 else (v & 0xff)
if t == str:
return 0
assert False, "unimplemented type %s" % str(t)
@ -100,8 +118,12 @@ def main():
help="Verbose logging (for this utility)")
for k, v in option_table.items():
parser.add_argument('--%s'%k, type=v.type, nargs='?', default=None,
help=v.desc)
if k == "support":
parser.add_argument('--%s'%k, default=None, action='store_true',
help=v.desc)
else:
parser.add_argument('--%s'%k, type=v.type, nargs='?', default=None,
help=v.desc)
args = parser.parse_args()
@ -110,7 +132,11 @@ def main():
resp = do_xfer(args, v.optid, val2byte(v.type, args.__dict__[k]), args.tty[0])
if resp is None:
return 1
if args.verbose: print("-> %d" % resp)
if k == "support":
print(", ".join(kvp[1] for kvp in supportmap.items() if (kvp[0] & resp) != 0))
else:
#if args.verbose:
print("-> %d" % resp)
return 0

View File

@ -5,6 +5,31 @@
#include "protos.h"
#include "rtconf.h"
#include "tempsensor.h"
enum {
implmap_val = 0
#ifdef DBOARD_HAS_CMSISDAP
| 1
#endif
#ifdef DBOARD_HAS_UART
| 2
#endif
// always true
/*#ifdef DBOARD_HAS_SERPROG
| 4
#endif*/
#ifdef DBOARD_HAS_I2C
| 4
#endif
#ifdef DBOARD_HAS_TEMPSENSOR
| 8
#endif
#ifdef USE_USBCDC_FOR_STDIO
| 128
#endif
};
uint8_t rtconf_do(uint8_t a, uint8_t b) {
switch ((enum rtconf_opt)a) {
@ -13,6 +38,20 @@ uint8_t rtconf_do(uint8_t a, uint8_t b) {
cdc_uart_set_hwflow(b != 0);
return 0;
#endif
#ifdef DBOARD_HAS_TEMPSENSOR
case opt_tempsense_enaddr: {
bool act = tempsense_get_active();
uint8_t addr = tempsense_get_addr();
printf("act=%c addr=%02x arg=%02x\n", act?'t':'f', addr, b);
uint8_t rv = tempsense_get_active() ? tempsense_get_addr() : 0xff;
if (b == 0x00) return rv;
else if (b == 0xff) tempsense_set_active(false);
else tempsense_set_addr(b);
return rv;
}
#endif
case opt_get_implmap:
return implmap_val;
default:
return 0xff;
}

View File

@ -13,6 +13,14 @@ enum rtconf_opt {
// return: 0
opt_uart_hwfc_endis = 1,
#endif
#ifdef DBOARD_HAS_TEMPSENSOR
// 0x00: get I2C address or enable/disable status
// 0xff: disable
//other: set I2C address
opt_tempsense_enaddr = 2,
#endif
opt_get_implmap = 0xff
};
uint8_t rtconf_do(uint8_t a, uint8_t b);

183
src/tempsensor.c Normal file
View File

@ -0,0 +1,183 @@
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include "protocfg.h"
#ifdef DBOARD_HAS_TEMPSENSOR
#include "tempsensor.h"
static bool active;
static uint8_t addr;
static uint8_t reg;
static size_t index;
static bool instartstop, hasreg;
enum regid {
config = 1,
t_upper,
t_lower,
t_crit,
t_a,
manuf_id,
dev_idrev,
reso
};
#define MANUF_ID 0x0054
#define DEV_IDREV 0x0400
struct {
uint16_t config;
uint16_t t_upper, t_lower, t_crit;
uint8_t reso;
} mcp9808;
void tempsense_init(void) {
active = false;
addr = 0xff;
reg = 0;
index = 0;
instartstop = false;
hasreg = false;
tempsense_dev_init();
}
bool tempsense_get_active(void) { return active; }
void tempsense_set_active(bool act) { active = act; if (!act) addr = 0xff; }
uint8_t tempsense_get_addr(void) { return addr; }
void tempsense_set_addr(uint8_t a) {
addr = a;
active = addr >= 0x8 && addr <= 0x77;
printf("set: ad=%02x ac=%c\n", addr, active?'t':'f');
}
void tempsense_do_start(void) {
//reg = 0;
index = 0;
instartstop = true;
hasreg = false;
}
void tempsense_do_stop(void) {
instartstop = false;
}
int tempsense_do_read(int length, uint8_t* buf) {
if (!instartstop || length < 0) return -1; // nak
if (length == 0) return 0; // ack
//if (!hasreg) return -1; // nak
int i;
for (i = 0; i < length; ++i, ++index) {
switch (reg) {
// TODO: big or little endian? seems to be big
case config:
if (index == 0) buf[0] = (mcp9808.config >> 8) & 0xff;
else if (index == 1) buf[1] = (mcp9808.config >> 0) & 0xff;
else return index;
case t_upper:
if (index == 0) buf[0] = (mcp9808.t_upper >> 8) & 0xff;
else if (index == 1) buf[1] = (mcp9808.t_upper >> 0) & 0xff;
else return index;
case t_lower:
if (index == 0) buf[0] = (mcp9808.t_lower >> 8) & 0xff;
else if (index == 1) buf[1] = (mcp9808.t_lower >> 0) & 0xff;
else return index;
case t_crit:
if (index == 0) buf[0] = (mcp9808.t_crit >> 8) & 0xff;
else if (index == 1) buf[1] = (mcp9808.t_crit >> 0) & 0xff;
else return index;
case t_a: {
static uint16_t temp;
if (index == 0) {
int16_t res = tempsense_dev_get_temp();
uint32_t tup = mcp9808.t_upper & 0x1ffc;
if (tup & 0x1000) tup |= 0xffffe000; // make negative
uint32_t tlo = mcp9808.t_lower & 0x1ffc;
if (tlo & 0x1000) tlo |= 0xffffe000; // make negative
uint32_t tcr = mcp9808.t_crit & 0x1ffc;
if (tcr & 0x1000) tcr |= 0xffffe000; // make negative
temp = res & 0x1fff; // data bits and sign bit
if ((int32_t)tlo > res) temp |= 0x2000;
if ((int32_t)tup < res) temp |= 0x4000;
if ((int32_t)tcr < res) temp |= 0x8000;
buf[0] = (temp >> 8) & 0xff;
} else if (index == 1) buf[1] = (temp>>0) & 0xff;
else return index;
}
case manuf_id:
if (index == 0) buf[0] = (MANUF_ID >> 8) & 0xff;
else if (index == 1) buf[1] = (MANUF_ID>>0)&0xff;
else return index;
case dev_idrev:
if (index == 0) buf[0] = (DEV_IDREV >> 8) & 0xff;
else if (index == 1) buf[1] = (DEV_IDREV>>0)&0xff;
else return index;
case reso:
if (index == 0) buf[0] = mcp9808.reso;
else return index;
default: return -1;
}
}
return i;
}
int tempsense_do_write(int length, const uint8_t* buf) {
if (!instartstop || length < 0) return -1; // nak
if (length == 0) return 0; // ack
if (!hasreg) {
reg = *buf & 0xf;
++buf;
--length;
hasreg = true;
}
if (length == 0) return 1; // ack, probably a read following
int i;
for (i = 0; i < length; ++i, ++index) {
switch (reg) {
case config:
if (index == 0) {
mcp9808.config = (mcp9808.config & 0x00ff) | ((uint16_t)buf[0] << 8);
} else if (index == 1) {
mcp9808.config = (mcp9808.config & 0xff00) | ((uint16_t)buf[1] << 0);
} else return index;
case t_upper:
if (index == 0) {
mcp9808.t_upper = (mcp9808.t_upper & 0x00ff) | ((uint16_t)buf[0] << 8);
} else if (index == 1) {
mcp9808.t_upper = (mcp9808.t_upper & 0xff00) | ((uint16_t)buf[1] << 0);
} else return index;
case t_lower:
if (index == 0) {
mcp9808.t_lower = (mcp9808.t_lower & 0x00ff) | ((uint16_t)buf[0] << 8);
} else if (index == 1) {
mcp9808.t_lower = (mcp9808.t_lower & 0xff00) | ((uint16_t)buf[1] << 0);
} else return index;
case t_crit:
if (index == 0) {
mcp9808.t_crit = (mcp9808.t_crit & 0x00ff) | ((uint16_t)buf[0] << 8);
} else if (index == 1) {
mcp9808.t_crit = (mcp9808.t_crit & 0xff00) | ((uint16_t)buf[1] << 0);
} else return index;
case reso:
mcp9808.reso = buf[index];
default: return -1;
}
}
return i;
}
#endif

27
src/tempsensor.h Normal file
View File

@ -0,0 +1,27 @@
#ifndef TEMPSENSOR_H_
#define TEMPSENSOR_H_
#include <stdint.h>
#include <stdbool.h>
void tempsense_init(void);
bool tempsense_get_active(void);
void tempsense_set_active(bool active);
uint8_t tempsense_get_addr(void);
void tempsense_set_addr(uint8_t addr);
void tempsense_do_start(void); // start cond
int tempsense_do_read(int length, uint8_t* buf);
int tempsense_do_write(int length, const uint8_t* buf);
void tempsense_do_stop(void); // stop cond
#ifdef DBOARD_HAS_TEMPSENSOR
void tempsense_dev_init(void);
// 8.4
int16_t tempsense_dev_get_temp(void);
#endif
#endif

View File

@ -7,13 +7,17 @@
#include <stdbool.h>
#include <stdio.h>
#include <hardware/i2c.h>
#include "tusb.h"
#include "device/usbd_pvt.h"
#include "protocfg.h"
#include "pinout.h"
#include "i2ctinyusb.h"
#include "pinout.h"
#include <hardware/i2c.h>
#include "tempsensor.h"
static uint8_t itf_num;
@ -28,6 +32,9 @@ static void iub_init(void) {
memset(&curcmd, 0, sizeof curcmd);
i2ctu_init();
#ifdef DBOARD_HAS_TEMPSENSOR
tempsense_init();
#endif
}
static void iub_reset(uint8_t rhport) {
@ -35,6 +42,9 @@ static void iub_reset(uint8_t rhport) {
memset(&curcmd, 0, sizeof curcmd);
i2ctu_init();
#ifdef DBOARD_HAS_TEMPSENSOR
tempsense_init();
#endif
itf_num = 0;
}
@ -54,10 +64,10 @@ static uint16_t iub_open(uint8_t rhport, tusb_desc_interface_t const* itf_desc,
}
static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t const* req) {
static char* stages[]={"SETUP","DATA","ACK"};
/*static char* stages[]={"SETUP","DATA","ACK"};
static char* types[]={"STD","CLS","VND","INV"};
/*printf("ctl req stage=%s rt=%s, wIndex=%04x, bReq=%02x, wValue=%04x wLength=%04x\n",
printf("ctl req stage=%s rt=%s, wIndex=%04x, bReq=%02x, wValue=%04x wLength=%04x\n",
stages[stage], types[req->bmRequestType_bit.type],
req->wIndex, req->bRequest, req->wValue, req->wLength);*/
@ -72,8 +82,17 @@ static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t co
//printf("WDATA a=%04hx l=%04hx ", cmd.addr, cmd.len);
//printf("data=%02x %02x...\n", rxbuf[0], rxbuf[1]);
status = i2ctu_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK,
cmd.addr, rxbuf, cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len);
#ifdef DBOARD_HAS_TEMPSENSOR
if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) {
if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start();
status = tempsense_do_write(cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len, rxbuf);
if (cmd.cmd & ITU_CMD_I2C_IO_END_F ) tempsense_do_stop ();
} else
#endif
{
status = i2ctu_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK,
cmd.addr, rxbuf, cmd.len > sizeof rxbuf ? sizeof rxbuf : cmd.len);
}
// cancel curcmd
curcmd.cmd = 0xff;
@ -133,8 +152,17 @@ static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t co
if (cmd.flags & I2C_M_RD) { // read from I2C device
//printf("read addr=%04hx len=%04hx ", cmd.addr, cmd.len);
status = i2ctu_read(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK,
cmd.addr, txbuf, cmd.len);
#ifdef DBOARD_HAS_TEMPSENSOR
if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) {
if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start();
status = tempsense_do_read(cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len, txbuf);
if (cmd.cmd & ITU_CMD_I2C_IO_END_F ) tempsense_do_stop ();
} else
#endif
{
status = i2ctu_read(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK,
cmd.addr, txbuf, cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len);
}
//printf("data=%02x %02x...\n", txbuf[0], txbuf[1]);
return tud_control_xfer(rhport, req, txbuf,
cmd.len > sizeof txbuf ? sizeof txbuf : cmd.len);
@ -142,8 +170,17 @@ static bool iub_ctl_req(uint8_t rhport, uint8_t stage, tusb_control_request_t co
//printf("write addr=%04hx len=%04hx ", cmd.addr, cmd.len);
if (cmd.len == 0) { // address probe -> do this here
uint8_t bleh = 0;
status = i2ctu_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK,
#ifdef DBOARD_HAS_TEMPSENSOR
if (tempsense_get_active() && tempsense_get_addr() == cmd.addr) {
if (cmd.cmd & ITU_CMD_I2C_IO_BEGIN_F) tempsense_do_start();
status = tempsense_do_write(0, &bleh);
if (cmd.cmd & ITU_CMD_I2C_IO_END_F ) tempsense_do_stop ();
} else
#endif
{
status = i2ctu_write(cmd.flags, cmd.cmd & ITU_CMD_I2C_IO_DIR_MASK,
cmd.addr, &bleh, 0);
}
//printf("probe -> %d\n", status);
return tud_control_status(rhport, req);
} else {