feat(amp): BLE SysEx R/W for AD85050 CH2 EQ RAM and I2C scan
Expose 0xA0-0xAE via 07 00/01 nibble-coded frames, add RAM helpers, and host scan/test scripts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
c480e96a3f
commit
3b0f5479ba
|
|
@ -727,6 +727,27 @@ uint8_t app_log_try_command(const char *cmd)
|
|||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "FLASH_ERASE_OK\n");
|
||||
return 1U;
|
||||
}
|
||||
if (strncmp(cmd, "i2c scan", 8) == 0) {
|
||||
uint8_t found[16];
|
||||
uint8_t n;
|
||||
uint8_t i;
|
||||
char line[48];
|
||||
|
||||
n = wk_i2c1_scan(found, (uint8_t)sizeof(found));
|
||||
for (i = 0U; i < n && i < (uint8_t)sizeof(found); i++) {
|
||||
if (found[i] == 0x30U) {
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "I2C ACK 0x30 AD85050\n");
|
||||
} else if (found[i] == 0x5AU) {
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "I2C ACK 0x5A AW816\n");
|
||||
} else {
|
||||
snprintf(line, sizeof(line), "I2C ACK 0x%02X\n", (unsigned)found[i]);
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
|
||||
}
|
||||
}
|
||||
snprintf(line, sizeof(line), "I2C_SCAN_END n=%u\n", (unsigned)n);
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, line);
|
||||
return 1U;
|
||||
}
|
||||
if (strncmp(cmd, "ui boot", 7) == 0) {
|
||||
/* 先 ACK:全屏 Logo 绘制很慢,避免 HIL/主机超时误判 */
|
||||
SEGGER_RTT_WriteString(APP_LOG_RTT_CHANNEL, "UI_BOOT_OK\n");
|
||||
|
|
|
|||
|
|
@ -231,6 +231,70 @@ AD85020B_StatusTypeDef AD85020B_I2C_Read(uint8_t reg, uint8_t *data)
|
|||
return AD85020B_I2C_ReadImpl(reg, data);
|
||||
}
|
||||
|
||||
static AD85020B_StatusTypeDef AD85020B_RamWaitClear(uint8_t mask)
|
||||
{
|
||||
uint8_t i;
|
||||
uint8_t st;
|
||||
|
||||
for (i = 0U; i < 20U; i++)
|
||||
{
|
||||
if (AD85020B_I2C_Read(AD85020B_REG_CFRW, &st) != AD85020B_OK)
|
||||
return AD85020B_ERROR;
|
||||
if ((st & mask) == 0U)
|
||||
return AD85020B_OK;
|
||||
wk_delay_ms(1);
|
||||
}
|
||||
return AD85020B_TIMEOUT;
|
||||
}
|
||||
|
||||
/* 手册:CFA 只收 7 位;表中 0xA0~0xAE 与 CH1 同址、靠 RBS 分 bank。
|
||||
Channel-2 EQ16/17/18 用 bank=1。 */
|
||||
AD85020B_StatusTypeDef AD85020B_RamWrite24(uint8_t ram_addr, uint8_t bank, uint32_t value)
|
||||
{
|
||||
uint8_t cfrw;
|
||||
|
||||
if (AD85020B_I2C_Write(AD85020B_REG_CFA, (uint8_t)(ram_addr & 0x7FU)) != AD85020B_OK)
|
||||
return AD85020B_ERROR;
|
||||
if (AD85020B_I2C_Write(AD85020B_REG_A1_T, (uint8_t)((value >> 16) & 0xFFU)) != AD85020B_OK)
|
||||
return AD85020B_ERROR;
|
||||
if (AD85020B_I2C_Write(AD85020B_REG_A1_M, (uint8_t)((value >> 8) & 0xFFU)) != AD85020B_OK)
|
||||
return AD85020B_ERROR;
|
||||
if (AD85020B_I2C_Write(AD85020B_REG_A1_B, (uint8_t)(value & 0xFFU)) != AD85020B_OK)
|
||||
return AD85020B_ERROR;
|
||||
|
||||
cfrw = (uint8_t)(AD85020B_CFRW_W1 | (bank ? AD85020B_CFRW_RBS : 0U));
|
||||
if (AD85020B_I2C_Write(AD85020B_REG_CFRW, cfrw) != AD85020B_OK)
|
||||
return AD85020B_ERROR;
|
||||
return AD85020B_RamWaitClear(AD85020B_CFRW_W1);
|
||||
}
|
||||
|
||||
AD85020B_StatusTypeDef AD85020B_RamRead24(uint8_t ram_addr, uint8_t bank, uint32_t *value)
|
||||
{
|
||||
uint8_t cfrw;
|
||||
uint8_t hi, mid, lo;
|
||||
|
||||
if (value == 0)
|
||||
return AD85020B_ERROR;
|
||||
if (AD85020B_I2C_Write(AD85020B_REG_CFA, (uint8_t)(ram_addr & 0x7FU)) != AD85020B_OK)
|
||||
return AD85020B_ERROR;
|
||||
|
||||
cfrw = (uint8_t)(AD85020B_CFRW_R1 | (bank ? AD85020B_CFRW_RBS : 0U));
|
||||
if (AD85020B_I2C_Write(AD85020B_REG_CFRW, cfrw) != AD85020B_OK)
|
||||
return AD85020B_ERROR;
|
||||
if (AD85020B_RamWaitClear(AD85020B_CFRW_R1) != AD85020B_OK)
|
||||
return AD85020B_TIMEOUT;
|
||||
|
||||
if (AD85020B_I2C_Read(AD85020B_REG_A1_T, &hi) != AD85020B_OK)
|
||||
return AD85020B_ERROR;
|
||||
if (AD85020B_I2C_Read(AD85020B_REG_A1_M, &mid) != AD85020B_OK)
|
||||
return AD85020B_ERROR;
|
||||
if (AD85020B_I2C_Read(AD85020B_REG_A1_B, &lo) != AD85020B_OK)
|
||||
return AD85020B_ERROR;
|
||||
|
||||
*value = ((uint32_t)hi << 16) | ((uint32_t)mid << 8) | (uint32_t)lo;
|
||||
return AD85020B_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief AD85020B 初始化
|
||||
* @retval AD85020B_StatusTypeDef: 初始化结果
|
||||
|
|
|
|||
|
|
@ -40,6 +40,23 @@
|
|||
#define AD85020B_REG_MVOL 0x03 // 主音量控制
|
||||
#define AD85020B_REG_HEADPHONEVOL 0x87 // 耳机音量控制
|
||||
|
||||
/* 系数 RAM 间接访问(手册 0x1D~0x2D) */
|
||||
#define AD85020B_REG_CFA 0x1D /* CFA[6:0] RAM 基址 */
|
||||
#define AD85020B_REG_A1_T 0x1E /* 系数 top [23:16] */
|
||||
#define AD85020B_REG_A1_M 0x1F /* 系数 middle [15:8] */
|
||||
#define AD85020B_REG_A1_B 0x20 /* 系数 bottom [7:0] */
|
||||
#define AD85020B_REG_CFRW 0x2D /* CfRW 读写触发 */
|
||||
#define AD85020B_CFRW_W1 0x01 /* 写单系数 */
|
||||
#define AD85020B_CFRW_WA 0x02
|
||||
#define AD85020B_CFRW_R1 0x04 /* 读单系数 */
|
||||
#define AD85020B_CFRW_RA 0x08
|
||||
#define AD85020B_CFRW_W3 0x10
|
||||
#define AD85020B_CFRW_R3 0x20
|
||||
#define AD85020B_CFRW_RBS 0x40 /* 0=bank0/CH1, 1=bank1/CH2 */
|
||||
|
||||
#define AD85020B_RAM_CH2_EQ16_A1 0xA0 /* CH2EQ16A1 */
|
||||
#define AD85020B_RAM_CH2_EQ18_A0 0xAE /* CH2EQ18A0 */
|
||||
|
||||
/* 软件复位配置:SCTL6寄存器BIT5=SW_RSTB,0=复位,1=正常 */
|
||||
#define AD85020B_SW_RESET 0x50 // BIT5=0(0x50二进制1010000,BIT5=0)
|
||||
#define AD85020B_SW_NORMAL 0x70 // BIT5=1(复位后恢复正常)
|
||||
|
|
@ -56,6 +73,8 @@ typedef enum
|
|||
void AD85020B_I2C_Init(void);
|
||||
AD85020B_StatusTypeDef AD85020B_I2C_Write(uint8_t reg, uint8_t data);
|
||||
AD85020B_StatusTypeDef AD85020B_I2C_Read(uint8_t reg, uint8_t *data);
|
||||
AD85020B_StatusTypeDef AD85020B_RamWrite24(uint8_t ram_addr, uint8_t bank, uint32_t value);
|
||||
AD85020B_StatusTypeDef AD85020B_RamRead24(uint8_t ram_addr, uint8_t bank, uint32_t *value);
|
||||
AD85020B_StatusTypeDef AD85020B_Init(void);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -61,7 +61,8 @@ extern "C" {
|
|||
void wk_i2c1_init(void);
|
||||
|
||||
/* add user code begin exported functions */
|
||||
|
||||
/* Probe I2C1 7-bit addresses 0x08..0x77 (address-only, no data write). */
|
||||
uint8_t wk_i2c1_scan(uint8_t *found, uint8_t max_found);
|
||||
/* add user code end exported functions */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -84,5 +84,66 @@ void wk_i2c1_init(void)
|
|||
}
|
||||
|
||||
/* add user code begin 1 */
|
||||
#include "i2c_application.h"
|
||||
|
||||
#define I2C_SCAN_ADDR_MIN 0x08U
|
||||
#define I2C_SCAN_ADDR_MAX 0x77U
|
||||
#define I2C_SCAN_TIMEOUT 8000U
|
||||
|
||||
extern i2c_status_type i2c_master_write_addr(i2c_handle_type *hi2c, uint16_t address, uint32_t timeout);
|
||||
|
||||
static void wk_i2c1_recover(void)
|
||||
{
|
||||
i2c_reset(I2C1);
|
||||
wk_i2c1_init();
|
||||
}
|
||||
|
||||
/* Address-only probe: START + 8-bit write address + STOP. No register write. */
|
||||
static uint8_t wk_i2c1_probe(uint8_t addr7)
|
||||
{
|
||||
i2c_handle_type hi2c;
|
||||
i2c_status_type status;
|
||||
uint16_t addr8;
|
||||
|
||||
memset(&hi2c, 0, sizeof(hi2c));
|
||||
hi2c.i2cx = I2C1;
|
||||
addr8 = (uint16_t)((uint16_t)addr7 << 1);
|
||||
|
||||
if (i2c_wait_flag(&hi2c, I2C_BUSYF_FLAG, I2C_EVENT_CHECK_NONE, I2C_SCAN_TIMEOUT) != I2C_OK) {
|
||||
wk_i2c1_recover();
|
||||
return 0U;
|
||||
}
|
||||
|
||||
status = i2c_master_write_addr(&hi2c, addr8, I2C_SCAN_TIMEOUT);
|
||||
if (status == I2C_OK) {
|
||||
i2c_flag_clear(I2C1, I2C_ADDR7F_FLAG);
|
||||
i2c_stop_generate(I2C1);
|
||||
(void)i2c_wait_flag(&hi2c, I2C_BUSYF_FLAG, I2C_EVENT_CHECK_NONE, I2C_SCAN_TIMEOUT);
|
||||
return 1U;
|
||||
}
|
||||
|
||||
i2c_stop_generate(I2C1);
|
||||
wk_i2c1_recover();
|
||||
return 0U;
|
||||
}
|
||||
|
||||
uint8_t wk_i2c1_scan(uint8_t *found, uint8_t max_found)
|
||||
{
|
||||
uint8_t n = 0U;
|
||||
uint8_t addr;
|
||||
|
||||
wk_i2c1_init();
|
||||
|
||||
for (addr = I2C_SCAN_ADDR_MIN; addr <= I2C_SCAN_ADDR_MAX; addr++) {
|
||||
if (wk_i2c1_probe(addr) != 0U) {
|
||||
if (found != 0 && n < max_found) {
|
||||
found[n] = addr;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
wk_i2c1_init();
|
||||
return n;
|
||||
}
|
||||
/* add user code end 1 */
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ static void handleSectionB(uint8_t *data);
|
|||
static void handleSectionC(uint8_t *data);
|
||||
static void handleSectionD(uint8_t *data);
|
||||
|
||||
static void handleAmpRamRead(uint8_t *data);
|
||||
static void handleAmpRamWrite(uint8_t *data);
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -149,6 +152,10 @@ static const BLE_SysExCmdItem bleSysExCmdTable[] =
|
|||
{{0x06, 0x06}, handleSectionB}, /* section B */
|
||||
{{0x06, 0x07}, handleSectionC}, /* section C */
|
||||
{{0x06, 0x08}, handleSectionD}, /* section D */
|
||||
|
||||
/*======== 7. amp RAM (AD85050 CH2 EQ16/17/18) 0x07 ========*/
|
||||
{{0x07, 0x00}, handleAmpRamRead}, /* read 24-bit coeff 0xA0..0xAE */
|
||||
{{0x07, 0x01}, handleAmpRamWrite}, /* write 24-bit coeff 0xA0..0xAE */
|
||||
};
|
||||
|
||||
// ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||
|
|
@ -856,6 +863,124 @@ static void handleRhythmStyle(uint8_t *data)
|
|||
}
|
||||
}
|
||||
|
||||
/*-------- 7. amp RAM 0x07 : AD85050 Channel-2 EQ16/17/18 (0xA0..0xAE) --------
|
||||
* BLE-MIDI SysEx 数据必须 <0x80,地址/24bit 值用半字节拆开:
|
||||
* 0xA0 -> 0A 00
|
||||
* 0x200000 -> 02 00 00 00 00 00
|
||||
* 读: F0 60 07 00 <regH> <regL> F7
|
||||
* 回: F0 60 07 00 <regH> <regL> <6 nibbles> F7
|
||||
* 写: F0 60 07 01 <regH> <regL> <6 nibbles> F7
|
||||
* 回: 同写帧;失败 F0 60 07 xx <regH> <regL> 7F F7
|
||||
*/
|
||||
#define AMP_RAM_BANK_CH2 1U
|
||||
|
||||
static uint8_t amp_parse_reg(const uint8_t *data, uint8_t *reg_out)
|
||||
{
|
||||
uint8_t hi = data[4];
|
||||
uint8_t lo = data[5];
|
||||
uint8_t reg;
|
||||
|
||||
if (hi > 0x0FU || lo > 0x0FU)
|
||||
return 0U;
|
||||
reg = (uint8_t)((hi << 4) | lo);
|
||||
if (reg < AD85020B_RAM_CH2_EQ16_A1 || reg > AD85020B_RAM_CH2_EQ18_A0)
|
||||
return 0U;
|
||||
*reg_out = reg;
|
||||
return 1U;
|
||||
}
|
||||
|
||||
static uint8_t amp_parse_u24(const uint8_t *nib, uint32_t *val_out)
|
||||
{
|
||||
uint8_t i;
|
||||
uint32_t v = 0;
|
||||
|
||||
for (i = 0U; i < 6U; i++)
|
||||
{
|
||||
if (nib[i] > 0x0FU)
|
||||
return 0U;
|
||||
v = (v << 4) | (uint32_t)nib[i];
|
||||
}
|
||||
*val_out = v;
|
||||
return 1U;
|
||||
}
|
||||
|
||||
static void amp_put_reg_nibbles(uint8_t *dst, uint8_t reg)
|
||||
{
|
||||
dst[0] = (uint8_t)((reg >> 4) & 0x0FU);
|
||||
dst[1] = (uint8_t)(reg & 0x0FU);
|
||||
}
|
||||
|
||||
static void amp_put_u24_nibbles(uint8_t *dst, uint32_t value)
|
||||
{
|
||||
dst[0] = (uint8_t)((value >> 20) & 0x0FU);
|
||||
dst[1] = (uint8_t)((value >> 16) & 0x0FU);
|
||||
dst[2] = (uint8_t)((value >> 12) & 0x0FU);
|
||||
dst[3] = (uint8_t)((value >> 8) & 0x0FU);
|
||||
dst[4] = (uint8_t)((value >> 4) & 0x0FU);
|
||||
dst[5] = (uint8_t)(value & 0x0FU);
|
||||
}
|
||||
|
||||
static void amp_send_fail(uint8_t sub, uint8_t reg)
|
||||
{
|
||||
uint8_t resp[8] = {0xF0, 0x60, 0x07, 0x00, 0x00, 0x00, 0x7F, 0xF7};
|
||||
resp[3] = sub;
|
||||
amp_put_reg_nibbles(&resp[4], reg);
|
||||
USART4_SendData(resp, sizeof(resp));
|
||||
}
|
||||
|
||||
static void amp_send_ok(uint8_t sub, uint8_t reg, uint32_t value)
|
||||
{
|
||||
uint8_t resp[13] = {0xF0, 0x60, 0x07, 0x00, 0, 0, 0, 0, 0, 0, 0, 0, 0xF7};
|
||||
resp[3] = sub;
|
||||
amp_put_reg_nibbles(&resp[4], reg);
|
||||
amp_put_u24_nibbles(&resp[6], value);
|
||||
USART4_SendData(resp, sizeof(resp));
|
||||
}
|
||||
|
||||
static void handleAmpRamRead(uint8_t *data)
|
||||
{
|
||||
uint8_t reg = 0;
|
||||
uint32_t value = 0;
|
||||
|
||||
if (amp_parse_reg(data, ®) == 0U)
|
||||
{
|
||||
amp_send_fail(0x00, (uint8_t)(((data[4] & 0x0FU) << 4) | (data[5] & 0x0FU)));
|
||||
return;
|
||||
}
|
||||
if (AD85020B_RamRead24(reg, AMP_RAM_BANK_CH2, &value) != AD85020B_OK)
|
||||
{
|
||||
amp_send_fail(0x00, reg);
|
||||
return;
|
||||
}
|
||||
LOG_I("AMP", "rd 0x%02X = 0x%06lX", (unsigned)reg, (unsigned long)value);
|
||||
amp_send_ok(0x00, reg, value);
|
||||
}
|
||||
|
||||
static void handleAmpRamWrite(uint8_t *data)
|
||||
{
|
||||
uint8_t reg = 0;
|
||||
uint32_t value = 0;
|
||||
|
||||
if (amp_parse_reg(data, ®) == 0U || amp_parse_u24(&data[6], &value) == 0U)
|
||||
{
|
||||
amp_send_fail(0x01, (uint8_t)(((data[4] & 0x0FU) << 4) | (data[5] & 0x0FU)));
|
||||
return;
|
||||
}
|
||||
if (AD85020B_RamWrite24(reg, AMP_RAM_BANK_CH2, value) != AD85020B_OK)
|
||||
{
|
||||
amp_send_fail(0x01, reg);
|
||||
return;
|
||||
}
|
||||
value = 0;
|
||||
if (AD85020B_RamRead24(reg, AMP_RAM_BANK_CH2, &value) != AD85020B_OK)
|
||||
{
|
||||
amp_send_fail(0x01, reg);
|
||||
return;
|
||||
}
|
||||
LOG_I("AMP", "wr 0x%02X = 0x%06lX", (unsigned)reg, (unsigned long)value);
|
||||
amp_send_ok(0x01, reg, value);
|
||||
}
|
||||
|
||||
/*-------- 5. reset / power off 0x05 --------*/
|
||||
/* F0 60 05 00 F7 : ack then soft power off (executed in main-loop context) */
|
||||
static void handleDeviceReset(uint8_t *data)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"""app 套件:App SysEx 全协议(组 01~06)。
|
||||
"""app 套件:App SysEx 全协议(组 01~07)。
|
||||
|
||||
- transport=com: 进程内复用 test_protocol_app_sim.run_tests(UART4 桥)
|
||||
- transport=ble: 子进程跑 test_protocol_ble.py( bleak + BLE-MIDI framing),
|
||||
|
|
|
|||
|
|
@ -0,0 +1,117 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Scan K1 I2C1 via RTT and report amp (0x30) / mic (0x5A)."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import time
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
from rtt_pitch_reg_test import ( # noqa: E402
|
||||
RttSession,
|
||||
connect_jlink,
|
||||
find_rtt_control_block,
|
||||
import_deps,
|
||||
wait_rtt_ready,
|
||||
)
|
||||
|
||||
ACK_RE = re.compile(r"^I2C ACK 0x([0-9A-Fa-f]{2})(?:\s+(\S+))?")
|
||||
END_RE = re.compile(r"^I2C_SCAN_END n=(\d+)")
|
||||
AMP_ADDR = 0x30
|
||||
MIC_ADDR = 0x5A
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if hasattr(sys.stdout, "reconfigure"):
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
import_deps()
|
||||
jlink = connect_jlink("AT32F403AC")
|
||||
try:
|
||||
cb = find_rtt_control_block(jlink)
|
||||
if cb is None:
|
||||
raise SystemExit("RTT CB not found")
|
||||
print(f"RTT CB @ 0x{cb:08X}", flush=True)
|
||||
jlink.rtt_start(cb)
|
||||
wait_rtt_ready(jlink)
|
||||
|
||||
sess = RttSession(jlink)
|
||||
sess.pump(0.3)
|
||||
|
||||
found: dict[int, str] = {}
|
||||
end_n: int | None = None
|
||||
|
||||
def consume(lines: list[str]) -> None:
|
||||
nonlocal end_n
|
||||
for line in lines:
|
||||
text = line.strip()
|
||||
if not text:
|
||||
continue
|
||||
if text.startswith("I2C "):
|
||||
print(text, flush=True)
|
||||
m = ACK_RE.match(text)
|
||||
if m:
|
||||
found[int(m.group(1), 16)] = m.group(2) or ""
|
||||
continue
|
||||
m = END_RE.match(text)
|
||||
if m:
|
||||
end_n = int(m.group(1))
|
||||
|
||||
for attempt in range(1, 5):
|
||||
mark = len(sess.lines)
|
||||
sess.cmd("i2c scan", settle=0.4)
|
||||
deadline = time.time() + 4.0
|
||||
while time.time() < deadline:
|
||||
consume(sess.lines[mark:])
|
||||
mark = len(sess.lines)
|
||||
if end_n is not None:
|
||||
break
|
||||
sess.pump(0.15)
|
||||
consume(sess.lines[mark:])
|
||||
if end_n is not None:
|
||||
break
|
||||
print(f"!! no I2C_SCAN_END (try {attempt}/4)", flush=True)
|
||||
|
||||
if end_n is None:
|
||||
print("FAIL: firmware did not answer I2C_SCAN_END", flush=True)
|
||||
return 1
|
||||
|
||||
others = [a for a in sorted(found) if a not in (AMP_ADDR, MIC_ADDR)]
|
||||
amp_ok = AMP_ADDR in found
|
||||
mic_ok = MIC_ADDR in found
|
||||
|
||||
print("", flush=True)
|
||||
print("======== I2C SCAN ========", flush=True)
|
||||
print(
|
||||
f"功放 AD85050 7bit 0x{AMP_ADDR:02X} / 写 0x{AMP_ADDR << 1:02X}: "
|
||||
f"{'FOUND' if amp_ok else 'MISSING'}",
|
||||
flush=True,
|
||||
)
|
||||
print(
|
||||
f"麦克风 AW816 7bit 0x{MIC_ADDR:02X} / 写 0x{MIC_ADDR << 1:02X}: "
|
||||
f"{'FOUND' if mic_ok else 'MISSING'}",
|
||||
flush=True,
|
||||
)
|
||||
if others:
|
||||
extra = " ".join(f"0x{a:02X}" for a in others)
|
||||
print(f"其它 ACK: {extra}", flush=True)
|
||||
else:
|
||||
print("其它 ACK: (无)", flush=True)
|
||||
print(f"I2C_SCAN_END n={end_n} unique={len(found)}", flush=True)
|
||||
return 0 if amp_ok and mic_ok else 2
|
||||
finally:
|
||||
try:
|
||||
jlink.rtt_stop()
|
||||
except Exception:
|
||||
pass
|
||||
jlink.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
|
@ -0,0 +1,121 @@
|
|||
#!/usr/bin/env python3
|
||||
"""BLE SysEx test: AD85050 CH2 EQ RAM 0xA0..0xAE read/write."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import time
|
||||
|
||||
from test_protocol_app_sim import Results, build, expect, hexs
|
||||
from test_protocol_ble import BleMidiSim, DEFAULT_NAME
|
||||
|
||||
|
||||
def u24_nibs(v: int) -> list[int]:
|
||||
return [(v >> s) & 0x0F for s in (20, 16, 12, 8, 4, 0)]
|
||||
|
||||
|
||||
def nibs_u24(n) -> int:
|
||||
v = 0
|
||||
for x in n:
|
||||
v = (v << 4) | (x & 0x0F)
|
||||
return v
|
||||
|
||||
|
||||
def reg_nibs(reg: int) -> tuple[int, int]:
|
||||
return (reg >> 4) & 0x0F, reg & 0x0F
|
||||
|
||||
|
||||
def main() -> int:
|
||||
if hasattr(sys.stdout, "reconfigure"):
|
||||
try:
|
||||
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
ap = argparse.ArgumentParser(description="K1 功放寄存器 BLE 读写测试")
|
||||
ap.add_argument("--ble-name", default=DEFAULT_NAME)
|
||||
ap.add_argument("--ble-address")
|
||||
ap.add_argument("--no-unpair", action="store_true")
|
||||
args = ap.parse_args()
|
||||
|
||||
print(f"连接 BLE {args.ble_name!r} {args.ble_address or ''} ...", flush=True)
|
||||
sim = BleMidiSim(
|
||||
name=args.ble_name,
|
||||
address=args.ble_address,
|
||||
transport="midi",
|
||||
unpair=not args.no_unpair,
|
||||
)
|
||||
R = Results()
|
||||
try:
|
||||
print(
|
||||
f"已连接 {sim.info.get('name')} {sim.info.get('address')}",
|
||||
flush=True,
|
||||
)
|
||||
|
||||
r = sim.query(build(0x01, 0x01), timeout=2.0)
|
||||
ok, d = expect(r, (0x60, 0x01, 0x01), 6)
|
||||
R.add("01 01 连接探测", "PASS" if ok else "FAIL", d)
|
||||
|
||||
targets = (
|
||||
(0xA0, "CH2EQ16A1"),
|
||||
(0xA4, "CH2EQ16A0"),
|
||||
(0xA5, "CH2EQ17A1"),
|
||||
(0xA9, "CH2EQ17A0"),
|
||||
(0xAA, "CH2EQ18A1"),
|
||||
(0xAE, "CH2EQ18A0"),
|
||||
)
|
||||
originals: dict[int, int] = {}
|
||||
|
||||
for reg, name in targets:
|
||||
rh, rl = reg_nibs(reg)
|
||||
r = sim.query(build(0x07, 0x00, rh, rl), timeout=1.5)
|
||||
ok, d = expect(r, (0x60, 0x07, 0x00, rh, rl), 13)
|
||||
if ok:
|
||||
val = nibs_u24(r[6:12])
|
||||
originals[reg] = val
|
||||
d += f" {name}=0x{val:06X}"
|
||||
R.add(f"07 00 读 0x{reg:02X} {name}", "PASS" if ok else "FAIL", d)
|
||||
|
||||
probe = 0x123456
|
||||
if 0xA4 in originals:
|
||||
rh, rl = reg_nibs(0xA4)
|
||||
r = sim.query(build(0x07, 0x01, rh, rl, *u24_nibs(probe)), timeout=1.5)
|
||||
ok, d = expect(r, (0x60, 0x07, 0x01, rh, rl), 13)
|
||||
if ok:
|
||||
got = nibs_u24(r[6:12])
|
||||
ok = got == probe
|
||||
d += f" wrote=0x{probe:06X} echo=0x{got:06X}"
|
||||
R.add("07 01 写 0xA4=0x123456", "PASS" if ok else "FAIL", d)
|
||||
|
||||
r = sim.query(build(0x07, 0x00, rh, rl), timeout=1.5)
|
||||
ok = r is not None and len(r) == 13 and nibs_u24(r[6:12]) == probe
|
||||
R.add("07 00 回读 0xA4=0x123456", "PASS" if ok else "FAIL", hexs(r))
|
||||
|
||||
r = sim.query(
|
||||
build(0x07, 0x01, rh, rl, *u24_nibs(originals[0xA4])), timeout=1.5
|
||||
)
|
||||
ok = r is not None and len(r) == 13 and nibs_u24(r[6:12]) == originals[0xA4]
|
||||
R.add(
|
||||
f"07 01 恢复 0xA4=0x{originals[0xA4]:06X}",
|
||||
"PASS" if ok else "FAIL",
|
||||
hexs(r),
|
||||
)
|
||||
else:
|
||||
R.add("07 01 写 0xA4", "SKIP", "读 0xA4 失败")
|
||||
R.add("07 00 回读 0xA4", "SKIP", "读 0xA4 失败")
|
||||
R.add("07 01 恢复 0xA4", "SKIP", "读 0xA4 失败")
|
||||
|
||||
rh, rl = reg_nibs(0xB0)
|
||||
r = sim.query(build(0x07, 0x00, rh, rl), timeout=1.5)
|
||||
ok = r is not None and len(r) == 8 and r[3] == 0x00 and r[6] == 0x7F
|
||||
R.add("07 00 非法地址 0xB0", "PASS" if ok else "FAIL", hexs(r))
|
||||
|
||||
time.sleep(0.05)
|
||||
return R.summary()
|
||||
finally:
|
||||
sim.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
|
|
@ -381,6 +381,44 @@ def run_tests(sim, allow_poweroff=False):
|
|||
R.add(f"06 {sub:02X} {name}", "SENT", "无应答属正常")
|
||||
time.sleep(0.05)
|
||||
|
||||
# ---------------- 7. 功放 RAM 0x07 (CH2 EQ16/17/18, 半字节编码) ----------------
|
||||
def _u24_nibs(v):
|
||||
return [(v >> s) & 0x0F for s in (20, 16, 12, 8, 4, 0)]
|
||||
|
||||
def _nibs_u24(n):
|
||||
v = 0
|
||||
for x in n:
|
||||
v = (v << 4) | (x & 0x0F)
|
||||
return v
|
||||
|
||||
r = sim.query(build(0x07, 0x00, 0x0A, 0x04), timeout=1.0)
|
||||
ok, d = expect(r, (0x60, 0x07, 0x00, 0x0A, 0x04), 13)
|
||||
orig_a4 = _nibs_u24(r[6:12]) if ok else None
|
||||
if ok:
|
||||
d += f" 0xA4=0x{orig_a4:06X}"
|
||||
R.add("07 00 读 CH2EQ16A0(0xA4)", "PASS" if ok else "FAIL", d)
|
||||
|
||||
if orig_a4 is not None:
|
||||
probe = 0x123456
|
||||
r = sim.query(build(0x07, 0x01, 0x0A, 0x04, *_u24_nibs(probe)), timeout=1.0)
|
||||
ok, d = expect(r, (0x60, 0x07, 0x01, 0x0A, 0x04), 13)
|
||||
if ok:
|
||||
got = _nibs_u24(r[6:12])
|
||||
ok = got == probe
|
||||
d += f" wrote=0x{probe:06X} read=0x{got:06X}"
|
||||
R.add("07 01 写 CH2EQ16A0=0x123456", "PASS" if ok else "FAIL", d)
|
||||
r = sim.query(build(0x07, 0x00, 0x0A, 0x04), timeout=1.0)
|
||||
ok = r is not None and len(r) == 13 and _nibs_u24(r[6:12]) == probe
|
||||
R.add("07 00 回读=0x123456", "PASS" if ok else "FAIL", hexs(r))
|
||||
sim.query(build(0x07, 0x01, 0x0A, 0x04, *_u24_nibs(orig_a4)), timeout=1.0)
|
||||
else:
|
||||
R.add("07 01 写 CH2EQ16A0", "SKIP", "读 0xA4 失败")
|
||||
R.add("07 00 回读", "SKIP", "读 0xA4 失败")
|
||||
|
||||
r = sim.query(build(0x07, 0x00, 0x0B, 0x00), timeout=1.0)
|
||||
ok = r is not None and len(r) == 8 and r[3] == 0x00 and r[6] == 0x7F
|
||||
R.add("07 00 非法地址 0xB0", "PASS" if ok else "FAIL", hexs(r))
|
||||
|
||||
# ---------------- 5. 复位/关机 0x05 ----------------
|
||||
if allow_poweroff:
|
||||
time.sleep(0.3)
|
||||
|
|
|
|||
Loading…
Reference in New Issue