반응형
ZSSC3230의 전체 측정(AAHEX
명령)은 센서 신호 컨디셔닝(SSC)을 적용하여 보정된 센서 데이터(24비트)와 온도 데이터(24비트)를 반환합니다. 이 과정은 NVM에 저장된 센서 설정과 보정 계수를 사용하므로, 측정 전에 관련 레지스터를 올바르게 설정해야 합니다. 아래는 필요한 NVM 레지스터와 설정 절차입니다.
1. 전체 측정 개요
AAHEX
명령: SSC 보정을 적용한 센서 데이터와 온도 데이터를 반환.- I2C 프레임:
[START] [48HEX + W] [AAHEX] [STOP]
- 응답: 상태 바이트(1바이트) + 센서 데이터(3바이트) + 온도 데이터(3바이트).
- 사용되는 NVM 레지스터: 센서 설정(
12HEX
,19HEX
), 보정 계수(03HEX
~18HEX
), 출력 설정(00HEX
,01HEX
,1AHEX
등). - 요구사항: 센서 특성(커패시턴스 범위, 유형)과 애플리케이션(출력 범위, 해상도)에 맞는 설정.
2. 설정해야 할 NVM 레지스터
전체 측정에 영향을 미치는 주요 NVM 레지스터는 다음과 같습니다(데이터시트 표 16, 28~32페이지):
NVM 주소 | 비트 | 필드 이름 | 설명 | 권장 설정 |
---|---|---|---|---|
00HEX | 3:0 | Out_res | 출력 해상도: 0000 (12비트) ~ 1111 (24비트). |
24비트(1111 ) 권장. |
5:4 | Out_mode | 출력 모드: 00 (센서+온도), 01 (센서), 10 (온도), 11 (예약). |
센서+온도(00 ). |
|
9:6 | Update_rate | 업데이트 속도: 0000 (최대, ~1.3ms) ~ 1111 (최소, ~21ms). |
애플리케이션에 따라 설정, 예: 0000 . |
|
10 | SSC_off | SSC 보정 비활성화: 0 (활성화), 1 (비활성화). |
활성화(0 ). |
|
01HEX | 15:0 | Output_min | 출력 최소값(16비트, 부호 있음). | 출력 범위에 따라 설정, 예: -32768(0x8000 ). |
02HEX | 15:0 | Output_max | 출력 최대값(16비트, 부호 있음). | 출력 범위에 따라 설정, 예: 32767(0x7FFF ). |
03HEX | 15:0 | Offset_S[15:0] | 센서 오프셋(24비트 하위). | 캘리브레이션 후 설정, 예: 0x0000 . |
04HEX | 15:0 | Gain_S[15:0] | 센서 게인(24비트 하위). | 캘리브레이션 후 설정, 예: 0x4000 . |
05HEX | 15:0 | Tcg[15:0] | 온도 게인 보정(24비트 하위). | 캘리브레이션 후 설정, 예: 0x0000 . |
06HEX | 15:0 | Tco[15:0] | 온도 오프셋 보정(24비트 하위). | 캘리브레이션 후 설정, 예: 0x0000 . |
0DHEX | 7:0 | Offset_S[23:16] | 센서 오프셋 상위. | 캘리브레이션 후 설정. |
15:8 | Gain_S[23:16] | 센서 게인 상위. | 캘리브레이션 후 설정. | |
0EHEX | 7:0 | Tco[23:16] | 온도 오프셋 상위. | 캘리브레이션 후 설정. |
15:8 | Tcg[23:16] | 온도 게인 상위. | 캘리브레이션 후 설정. | |
12HEX | 5:0 | shift_cap | 제로-시프트 커패시턴스: 0.0pF(00 0000 ) ~ 15.75pF(11 1111 ). |
센서 범위 이내, 예: 0.25pF(00 0001 ). |
7:6 | adc_bits | ADC 해상도: 00 (12비트), 01 (14비트), 10 (16비트), 11 (18비트). |
14비트(01 ) 권장. |
|
8 | noise_mode | 노이즈 품질: 0 (저전류), 1 (저노이즈). |
저노이즈(1 ). |
|
13:9 | cap_range | 최대 커패시턴스: 0.5pF(00000 ) ~ 16.0pF(11111 ). |
센서에 맞게, 예: 2.0pF(00010 ). |
|
14 | sensor_leakage | 누설 전류 보상: 0 (비활성화), 1 (활성화). |
필요 시 1 , 기본 0 . |
|
19HEX | 1:0 | CC_pin_selection | 측정 핀: 00 (없음), 01 (CC), 10 (CC’), 11 (CC+CC’). |
예: CC(01 ). |
2 | Dither | 디지털 디더링: 0 (비활성화), 1 (활성화). |
EMI 우려 시 1 , 기본 0 . |
|
3 | En_sh2 | 감산 모드: 0 (비활성화), 1 (활성화). |
단일 끝 모드 시 1 , 기본 0 . |
|
4 | En_shlddrv | 액티브 쉴드: 0 (비활성화), 1 (활성화). |
쉴드 필요 시 1 , 기본 0 . |
|
5 | Dyn_imp | 고전류 구동: 0 (비활성화), 1 (활성화). |
작은 센서 시 1 , 기본 0 . |
|
6 | Test_cap | 내부 커패시터(~2pF): 0 (비활성화), 1 (활성화). |
테스트용 1 , 기본 0 . |
|
1AHEX | 2:0 | SSC_freq | SSC 업데이트 주파수: 000 (최대) ~ 111 (최소). |
애플리케이션에 따라, 예: 000 . |
3. 설정 절차
- 센서 및 애플리케이션 특성 확인:
- 센서: 커패시턴스 범위(예: 2pF), 유형(차동/단일 끝), 핀(CC/CC’).
- 출력: 해상도(예: 24비트), 범위(예: -32768 ~ 32767).
- 예: 차동 센서, 2pF, CC 핀, 24비트 출력, 빠른 업데이트.
- 커맨드 모드 진입:
A9HEX
명령으로 커맨드 모드 진입.- I2C 프레임:
[START] [48HEX + W] [A9HEX] [STOP]
, 상태 바이트 확인.
- PDM 비활성화:
- 주기적 측정 모드 비활성화(
B4HEX
). - I2C 프레임:
[START] [48HEX + W] [B4HEX] [STOP]
.
- 주기적 측정 모드 비활성화(
- NVM 설정 쓰기:
- 00HEX: 출력 해상도(24비트,
1111
), 모드(센서+온도,00
), 빠른 업데이트(0000
), SSC 활성화(0
).- 예:
0x0F00
(Out_res=1111
,Out_mode=00
,Update_rate=0000
,SSC_off=0
). - 프레임:
[START] [48HEX + W] [20HEX] [0FHEX] [00HEX] [STOP]
.
- 예:
- 01HEX: 출력 최소값, 예: -32768(
0x8000
).- 프레임:
[START] [48HEX + W] [21HEX] [80HEX] [00HEX] [STOP]
.
- 프레임:
- 02HEX: 출력 최대값, 예: 32767(
0x7FFF
).- 프레임:
[START] [48HEX + W] [22HEX] [7FHEX] [FFHEX] [STOP]
.
- 프레임:
- 03HEX ~ 0EHEX: 보정 계수(
Offset_S
,Gain_S
,Tcg
,Tco
등).- 캘리브레이션 데이터로 설정, 예:
Offset_S=0x000000
,Gain_S=0x004000
. - 프레임:
[START] [48HEX + W] [23HEX] [00HEX] [00HEX] [STOP]
(03HEX
).
- 캘리브레이션 데이터로 설정, 예:
- 12HEX: 차동(
0
),cap_range=2pF
(00010
), 14비트(01
), 저노이즈(1
),shift_cap=0.25pF
(000001
).- 예:
0x4102
. - 프레임:
[START] [48HEX + W] [32HEX] [41HEX] [02HEX] [STOP]
.
- 예:
- 19HEX: CC 핀(
01
), 기타 비활성화.- 예:
0x0001
. - 프레임:
[START] [48HEX + W] [39HEX] [00HEX] [01HEX] [STOP]
.
- 예:
- 1AHEX: SSC 주파수(
000
).- 예:
0x0000
. - 프레임:
[START] [48HEX + W] [3AHEX] [00HEX] [00HEX] [STOP]
.
- 예:
- 00HEX: 출력 해상도(24비트,
- 체크섬 계산:
90HEX
로 체크섬 계산(1CHEX
에 저장).- 프레임:
[START] [48HEX + W] [90HEX] [STOP]
.
- 설정 검증:
00HEX
,01HEX
,02HEX
,03HEX~0EHEX
,12HEX
,19HEX
,1AHEX
읽기.- CRC 검증(
1CHEX
).
- 전체 측정 수행:
AAHEX
명령으로 측정.- 프레임:
[START] [48HEX + W] [AAHEX] [STOP]
, 응답: 상태 + 24비트 센서 + 24비트 온도.
4. STM32L432KC 예제 코드
아래는 STM32L432KC에서 전체 측정 전 NVM 설정과 모든 명령어를 구현한 코드입니다(STMCube HAL 사용, 차동 센서, 2pF, 14비트, CC 핀, 24비트 출력, 빠른 업데이트).
/* STM32L432KC I2C를 사용한 ZSSC3230 전체 명령어 및 전체 측정 설정
* - STM32Cube HAL 라이브러리 사용
* - ZSSC3230 I2C 주소: 0x48 (7비트)
* - NVM 설정: 차동 센서, 2pF, 14비트, CC 핀, 24비트 출력, 빠른 업데이트
* - 기능: 모든 명령어, 24비트 계수, CRC 검증, PDM 비활성화, 전체 측정 전 설정
*/
#include "stm32l4xx_hal.h"
#include <string.h>
#include <stdio.h>
/* I2C 핸들 */
extern I2C_HandleTypeDef hi2c1;
/* ZSSC3230 정의 */
#define ZSSC3230_I2C_ADDR (0x48 << 1)
#define NVM_START_ADDR 0x00
#define NVM_END_ADDR 0x1C
#define CRC_ADDR 0x1C
#define DEFAULT_TIMEOUT_MS 100
/* 24비트 계수 정의 */
typedef struct {
uint8_t lsb_addr;
uint8_t msb_addr;
uint8_t msb_shift;
} CoefficientMap;
static const CoefficientMap coeff_map[] = {
{0x03, 0x0D, 8}, {0x04, 0x0D, 0}, {0x05, 0x0E, 8}, {0x06, 0x0E, 0},
{0x07, 0x0F, 8}, {0x08, 0x0F, 0}, {0x09, 0x10, 8}, {0x0A, 0x10, 0},
{0x0B, 0x11, 8}, {0x0C, 0x11, 0}, {0x16, 0x18, 0}, {0x17, 0x18, 8},
{0x13, 0x15, 0}, {0x14, 0x15, 8}
};
/* 상태 바이트 확인 */
HAL_StatusTypeDef check_status_byte(uint8_t status) {
if (status == 0x00) return HAL_OK;
printf("Error: Status byte 0x%02X\n", status);
return HAL_ERROR;
}
/* 커맨드 모드 진입 (A9HEX) */
HAL_StatusTypeDef zssc3230_start_command_mode(uint32_t timeout_ms) {
uint8_t cmd = 0xA9;
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, &cmd, 1, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to enter command mode: HAL error %d\n", ret);
return ret;
}
uint8_t status;
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, &status, 1, timeout_ms);
return (ret == HAL_OK) ? check_status_byte(status) : ret;
}
/* 슬립 모드 진입 (A8HEX) */
HAL_StatusTypeDef zssc3230_start_sleep(uint32_t timeout_ms) {
uint8_t cmd = 0xA8;
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, &cmd, 1, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to enter sleep mode: HAL error %d\n", ret);
return ret;
}
uint8_t status;
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, &status, 1, timeout_ms);
return (ret == HAL_OK) ? check_status_byte(status) : ret;
}
/* 주기적 측정 모드 (ABHEX) */
HAL_StatusTypeDef zssc3230_start_cyclic_mode(uint32_t *sensor_data, uint32_t *temp_data, uint32_t timeout_ms) {
uint8_t cmd = 0xAB;
uint8_t rx_buffer[7];
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, &cmd, 1, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to start cyclic mode: HAL error %d\n", ret);
return ret;
}
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, rx_buffer, 7, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to receive data after ABHEX: HAL error %d\n", ret);
return ret;
}
ret = check_status_byte(rx_buffer[0]);
if (ret != HAL_OK) return ret;
*sensor_data = (rx_buffer[1] << 16) | (rx_buffer[2] << 8) | rx_buffer[3];
*temp_data = (rx_buffer[4] << 16) | (rx_buffer[5] << 8) | rx_buffer[6];
return HAL_OK;
}
/* PDM 비활성화 (B4HEX) */
HAL_StatusTypeDef zssc3230_stop_pdm(uint32_t timeout_ms) {
uint8_t cmd = 0xB4;
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, &cmd, 1, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to stop PDM: HAL error %d\n", ret);
}
return ret;
}
/* NVM 읽기 (00HEX ~ 1FHEX) */
HAL_StatusTypeDef zssc3230_nvm_read(uint8_t addr, uint16_t *data, uint32_t timeout_ms) {
uint8_t cmd = addr;
uint8_t rx_buffer[3];
HAL_StatusTypeDef ret;
if (addr > NVM_END_ADDR) {
printf("Invalid NVM address: 0x%02X\n", addr);
return HAL_ERROR;
}
ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, &cmd, 1, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to send read command 0x%02X: HAL error %d\n", cmd, ret);
return ret;
}
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, rx_buffer, 3, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to receive data for address 0x%02X: HAL error %d\n", addr, ret);
return ret;
}
ret = check_status_byte(rx_buffer[0]);
if (ret != HAL_OK) return ret;
*data = (rx_buffer[1] << 8) | rx_buffer[2];
return HAL_OK;
}
/* NVM 쓰기 (20HEX ~ 3CHEX) */
HAL_StatusTypeDef zssc3230_nvm_write(uint8_t addr, uint16_t data, uint32_t timeout_ms) {
uint8_t tx_buffer[3] = {0x20 + addr, (data >> 8) & 0xFF, data & 0xFF};
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, tx_buffer, 3, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to write to address 0x%02X: HAL error %d\n", addr, ret);
return ret;
}
uint8_t status;
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, &status, 1, timeout_ms);
return (ret == HAL_OK) ? check_status_byte(status) : ret;
}
/* NVM 체크섬 계산 (90HEX) */
HAL_StatusTypeDef zssc3230_calculate_nvm_checksum(uint32_t timeout_ms) {
uint8_t cmd = 0x90;
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, &cmd, 1, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to calculate checksum: HAL error %d\n", ret);
return ret;
}
uint8_t status;
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, &status, 1, timeout_ms);
return (ret == HAL_OK) ? check_status_byte(status) : ret;
}
/* 원시 센서 측정 (A2HEX) */
HAL_StatusTypeDef zssc3230_raw_sensor_measure(uint32_t *data, uint32_t timeout_ms) {
uint8_t tx_buffer[3] = {0xA2, 0x00, 0x00};
uint8_t rx_buffer[4];
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, tx_buffer, 3, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to send A2HEX: HAL error %d\n", ret);
return ret;
}
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, rx_buffer, 4, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to receive data after A2HEX: HAL error %d\n", ret);
return ret;
}
ret = check_status_byte(rx_buffer[0]);
if (ret != HAL_OK) return ret;
*data = (rx_buffer[1] << 16) | (rx_buffer[2] << 8) | rx_buffer[3];
return HAL_OK;
}
/* 사용자 설정 원시 센서 측정 (A3HEX) */
HAL_StatusTypeDef zssc3230_raw_sensor_measure_custom(uint16_t config, uint32_t *data, uint32_t timeout_ms) {
uint8_t tx_buffer[3] = {0xA3, (config >> 8) & 0xFF, config & 0xFF};
uint8_t rx_buffer[4];
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, tx_buffer, 3, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to send A3HEX: HAL error %d\n", ret);
return ret;
}
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, rx_buffer, 4, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to receive data after A3HEX: HAL error %d\n", ret);
return ret;
}
ret = check_status_byte(rx_buffer[0]);
if (ret != HAL_OK) return ret;
*data = (rx_buffer[1] << 16) | (rx_buffer[2] << 8) | rx_buffer[3];
return HAL_OK;
}
/* 원시 온도 측정 (A6HEX) */
HAL_StatusTypeDef zssc3230_raw_temp_measure(uint32_t *data, uint32_t timeout_ms) {
uint8_t tx_buffer[3] = {0xA6, 0x00, 0x00};
uint8_t rx_buffer[4];
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, tx_buffer, 3, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to send A6HEX: HAL error %d\n", ret);
return ret;
}
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, rx_buffer, 4, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to receive data after A6HEX: HAL error %d\n", ret);
return ret;
}
ret = check_status_byte(rx_buffer[0]);
if (ret != HAL_OK) return ret;
*data = (rx_buffer[1] << 16) | (rx_buffer[2] << 8) | rx_buffer[3];
return HAL_OK;
}
/* 전체 측정 (AAHEX) */
HAL_StatusTypeDef zssc3230_measure(uint32_t *sensor_data, uint32_t *temp_data, uint32_t timeout_ms) {
uint8_t cmd = 0xAA;
uint8_t rx_buffer[7];
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, &cmd, 1, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to send AAHEX: HAL error %d\n", ret);
return ret;
}
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, rx_buffer, 7, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to receive data after AAHEX: HAL error %d\n", ret);
return ret;
}
ret = check_status_byte(rx_buffer[0]);
if (ret != HAL_OK) return ret;
*sensor_data = (rx_buffer[1] << 16) | (rx_buffer[2] << 8) | rx_buffer[3];
*temp_data = (rx_buffer[4] << 16) | (rx_buffer[5] << 8) | rx_buffer[6];
return HAL_OK;
}
/* 오버샘플링 측정 (ACHEX, ADHEX, AEHEX, AFHEX) */
HAL_StatusTypeDef zssc3230_oversample_measure(uint8_t oversample_cmd, uint32_t *sensor_data, uint32_t *temp_data, uint32_t timeout_ms) {
if (oversample_cmd != 0xAC && oversample_cmd != 0xAD && oversample_cmd != 0xAE && oversample_cmd != 0xAF) {
printf("Invalid oversample command: 0x%02X\n", oversample_cmd);
return HAL_ERROR;
}
uint8_t cmd = oversample_cmd;
uint8_t rx_buffer[7];
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, &cmd, 1, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to send 0x%02X: HAL error %d\n", cmd, ret);
return ret;
}
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, rx_buffer, 7, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to receive data after 0x%02X: HAL error %d\n", cmd, ret);
return ret;
}
ret = check_status_byte(rx_buffer[0]);
if (ret != HAL_OK) return ret;
*sensor_data = (rx_buffer[1] << 16) | (rx_buffer[2] << 8) | rx_buffer[3];
*temp_data = (rx_buffer[4] << 16) | (rx_buffer[5] << 8) | rx_buffer[6];
return HAL_OK;
}
/* 브로큰 칩 테스트 (B0HEX) */
HAL_StatusTypeDef zssc3230_broken_chip_test(uint16_t *result, uint32_t timeout_ms) {
uint8_t cmd = 0xB0;
uint8_t rx_buffer[3];
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, &cmd, 1, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to send B0HEX: HAL error %d\n", ret);
return ret;
}
ret = HAL_I2C_Master_Receive(&hi2c1, ZSSC3230_I2C_ADDR, rx_buffer, 3, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to receive data after B0HEX: HAL error %d\n", ret);
return ret;
}
ret = check_status_byte(rx_buffer[0]);
if (ret != HAL_OK) return ret;
*result = (rx_buffer[1] << 8) | rx_buffer[2];
return HAL_OK;
}
/* 소프트 리셋 (FXHEX) */
HAL_StatusTypeDef zssc3230_soft_reset(uint32_t timeout_ms) {
uint8_t tx_buffer[2] = {0xF0, 0x00};
HAL_StatusTypeDef ret = HAL_I2C_Master_Transmit(&hi2c1, ZSSC3230_I2C_ADDR, tx_buffer, 2, timeout_ms);
if (ret != HAL_OK) {
printf("Soft reset failed: HAL error %d\n", ret);
}
return ret;
}
/* 24비트 계수 읽기 */
HAL_StatusTypeDef zssc3230_nvm_read_24bit(uint8_t coeff_idx, int32_t *value, uint32_t timeout_ms) {
if (coeff_idx >= sizeof(coeff_map) / sizeof(coeff_map[0])) {
printf("Invalid coefficient index: %d\n", coeff_idx);
return HAL_ERROR;
}
uint16_t lsb_data, msb_data;
HAL_StatusTypeDef ret = zssc3230_nvm_read(coeff_map[coeff_idx].lsb_addr, &lsb_data, timeout_ms);
if (ret != HAL_OK) return ret;
ret = zssc3230_nvm_read(coeff_map[coeff_idx].msb_addr, &msb_data, timeout_ms);
if (ret != HAL_OK) return ret;
uint32_t raw = ((msb_data >> coeff_map[coeff_idx].msb_shift) & 0xFF) << 16 | lsb_data;
*value = (raw & 0x800000) ? (int32_t)(raw | 0xFF000000) : (int32_t)raw;
return HAL_OK;
}
/* 24비트 계수 쓰기 */
HAL_StatusTypeDef zssc3230_nvm_write_24bit(uint8_t coeff_idx, int32_t value, uint32_t timeout_ms) {
if (coeff_idx >= sizeof(coeff_map) / sizeof(coeff_map[0])) {
printf("Invalid coefficient index: %d\n", coeff_idx);
return HAL_ERROR;
}
HAL_StatusTypeDef ret;
uint16_t lsb_data = value & 0xFFFF;
uint16_t msb_data;
ret = zssc3230_nvm_read(coeff_map[coeff_idx].msb_addr, &msb_data, timeout_ms);
if (ret != HAL_OK) return ret;
uint8_t shift = coeff_map[coeff_idx].msb_shift;
uint8_t mask = (shift == 0) ? 0xFF00 : 0x00FF;
msb_data = (msb_data & mask) | (((value >> 16) & 0xFF) << shift);
ret = zssc3230_nvm_write(coeff_map[coeff_idx].lsb_addr, lsb_data, timeout_ms);
if (ret != HAL_OK) return ret;
ret = zssc3230_nvm_write(coeff_map[coeff_idx].msb_addr, msb_data, timeout_ms);
return ret;
}
/* NVM 전체 읽기 */
HAL_StatusTypeDef zssc3230_nvm_read_all(uint16_t *data_buffer, uint32_t timeout_ms) {
HAL_StatusTypeDef ret = zssc3230_start_command_mode(timeout_ms);
if (ret != HAL_OK) return ret;
for (uint8_t addr = NVM_START_ADDR; addr <= NVM_END_ADDR; addr++) {
ret = zssc3230_nvm_read(addr, &data_buffer[addr], timeout_ms);
if (ret != HAL_OK) return ret;
}
return HAL_OK;
}
/* NVM 전체 쓰기 */
HAL_StatusTypeDef zssc3230_nvm_write_all(uint16_t *data_buffer, uint32_t timeout_ms) {
HAL_StatusTypeDef ret = zssc3230_start_command_mode(timeout_ms);
if (ret != HAL_OK) return ret;
ret = zssc3230_stop_pdm(timeout_ms);
if (ret != HAL_OK) return ret;
for (uint8_t addr = NVM_START_ADDR; addr <= NVM_END_ADDR; addr++) {
ret = zssc3230_nvm_write(addr, data_buffer[addr], timeout_ms);
if (ret != HAL_OK) return ret;
}
ret = zssc3230_calculate_nvm_checksum(timeout_ms);
return ret;
}
/* CRC 계산 */
uint16_t zssc3230_calculate_crc(uint16_t *data_buffer) {
uint32_t crc = 0;
uint16_t poly = 0x8005;
for (uint8_t addr = NVM_START_ADDR; addr < NVM_END_ADDR; addr++) {
uint16_t data = data_buffer[addr];
for (int i = 15; i >= 0; i--) {
uint32_t bit = (crc >> 15) ^ ((data >> i) & 1);
crc = (crc << 1) | bit;
if (bit) crc ^= poly;
}
}
return (uint16_t)(crc & 0xFFFF);
}
/* CRC 검증 */
HAL_StatusTypeDef zssc3230_verify_crc(uint16_t *data_buffer, uint32_t timeout_ms) {
uint16_t calc_crc = zssc3230_calculate_crc(data_buffer);
uint16_t stored_crc;
HAL_StatusTypeDef ret = zssc3230_nvm_read(CRC_ADDR, &stored_crc, timeout_ms);
if (ret != HAL_OK) {
printf("Failed to read stored CRC\n");
return ret;
}
if (calc_crc == stored_crc) {
printf("CRC verification passed (0x%04X)\n", calc_crc);
return HAL_OK;
} else {
printf("CRC verification failed (Calculated: 0x%04X, Stored: 0x%04X)\n", calc_crc, stored_crc);
return HAL_ERROR;
}
}
/* 전체 측정 전 NVM 설정 */
HAL_StatusTypeDef zssc3230_setup_full_measurement(uint32_t timeout_ms) {
HAL_StatusTypeDef ret;
// 1. 커맨드 모드 진입
ret = zssc3230_start_command_mode(timeout_ms);
if (ret != HAL_OK) return ret;
printf("Command mode entered\n");
// 2. PDM 비활성화
ret = zssc3230_stop_pdm(timeout_ms);
if (ret != HAL_OK) return ret;
printf("PDM stopped\n");
// 3. 00HEX 설정 (24비트, 센서+온도, 빠른 업데이트, SSC 활성화)
uint16_t reg_00 = (0 << 10) | // SSC_off: 0
(0 << 6) | // Update_rate: 0000
(0 << 4) | // Out_mode: 00
(15); // Out_res: 1111 (24비트)
ret = zssc3230_nvm_write(0x00, reg_00, timeout_ms);
if (ret != HAL_OK) return ret;
printf("NVM[0x00] set to 0x%04X\n", reg_00);
// 4. 01HEX 설정 (출력 최소값: -32768)
ret = zssc3230_nvm_write(0x01, 0x8000, timeout_ms);
if (ret != HAL_OK) return ret;
printf("NVM[0x01] set to 0x8000\n");
// 5. 02HEX 설정 (출력 최대값: 32767)
ret = zssc3230_nvm_write(0x02, 0x7FFF, timeout_ms);
if (ret != HAL_OK) return ret;
printf("NVM[0x02] set to 0x7FFF\n");
// 6. 보정 계수 설정 (예: 기본값)
uint16_t calib_data[] = {0x0000, 0x4000, 0x0000, 0x0000}; // Offset_S, Gain_S, Tcg, Tco
uint8_t calib_addrs[] = {0x03, 0x04, 0x05, 0x06};
for (int i = 0; i < 4; i++) {
ret = zssc3230_nvm_write(calib_addrs[i], calib_data[i], timeout_ms);
if (ret != HAL_OK) return ret;
printf("NVM[0x%02X] set to 0x%04X\n", calib_addrs[i], calib_data[i]);
}
ret = zssc3230_nvm_write(0x0D, 0x0000, timeout_ms); // Offset_S[23:16], Gain_S[23:16]
if (ret != HAL_OK) return ret;
printf("NVM[0x0D] set to 0x0000\n");
ret = zssc3230_nvm_write(0x0E, 0x0000, timeout_ms); // Tcg[23:16], Tco[23:16]
if (ret != HAL_OK) return ret;
printf("NVM[0x0E] set to 0x0000\n");
// 7. 12HEX 설정 (차동, 2pF, 14비트, 저노이즈, shift_cap=0.25pF)
uint16_t reg_12 = (0 << 15) | // sensecap_type: 차동
(0 << 14) | // sensor_leakage: 비활성화
(2 << 9) | // cap_range: 2.0pF
(1 << 8) | // noise_mode: 저노이즈
(1 << 6) | // adc_bits: 14비트
(1); // shift_cap: 0.25pF
ret = zssc3230_nvm_write(0x12, reg_12, timeout_ms);
if (ret != HAL_OK) return ret;
printf("NVM[0x12] set to 0x%04X\n", reg_12);
// 8. 19HEX 설정 (CC 핀)
uint16_t reg_19 = (1 << 0); // CC_pin_selection: CC
ret = zssc3230_nvm_write(0x19, reg_19, timeout_ms);
if (ret != HAL_OK) return ret;
printf("NVM[0x19] set to 0x%04X\n", reg_19);
// 9. 1AHEX 설정 (SSC 주파수: 최대)
ret = zssc3230_nvm_write(0x1A, 0x0000, timeout_ms);
if (ret != HAL_OK) return ret;
printf("NVM[0x1A] set to 0x0000\n");
// 10. 체크섬 계산
ret = zssc3230_calculate_nvm_checksum(timeout_ms);
if (ret != HAL_OK) return ret;
printf("Checksum calculated\n");
return HAL_OK;
}
/* 메인 함수 예제 */
void zssc3230_command_example(void) {
HAL_StatusTypeDef ret;
uint16_t nvm_data[29];
uint32_t sensor_data, temp_data;
uint16_t result;
uint32_t timeout_ms = DEFAULT_TIMEOUT_MS;
// 1. 전체 측정 전 NVM 설정
ret = zssc3230_setup_full_measurement(timeout_ms);
if (ret != HAL_OK) {
printf("Full measurement setup failed\n");
return;
}
// 2. 전체 측정 (AAHEX)
ret = zssc3230_measure(&sensor_data, &temp_data, timeout_ms);
if (ret == HAL_OK) {
printf("SSC-corrected sensor: 0x%06X, temp: 0x%06X\n", sensor_data, temp_data);
} else {
printf("Full measurement failed\n");
}
// 3. 원시 센서 측정 (A2HEX)
ret = zssc3230_raw_sensor_measure(&sensor_data, timeout_ms);
if (ret == HAL_OK) printf("Raw sensor data: 0x%06X\n", sensor_data);
else printf("Raw sensor measurement failed\n");
// 4. 사용자 설정 원시 센서 측정 (A3HEX)
uint16_t config = 0x4102; // 12HEX 상위 + 19HEX 하위
ret = zssc3230_raw_sensor_measure_custom(config, &sensor_data, timeout_ms);
if (ret == HAL_OK) printf("Custom raw sensor data: 0x%06X\n", sensor_data);
else printf("Custom raw sensor measurement failed\n");
// 5. NVM 전체 읽기 및 CRC 검증
ret = zssc3230_nvm_read_all(nvm_data, timeout_ms);
if (ret == HAL_OK) {
printf("NVM read all succeeded:\n");
for (uint8_t i = 0; i <= NVM_END_ADDR; i++) {
printf("NVM[0x%02X] = 0x%04X\n", i, nvm_data[i]);
}
ret = zssc3230_verify_crc(nvm_data, timeout_ms);
} else {
printf("NVM read all failed\n");
}
// 6. 24비트 계수 쓰기/읽기 (Tcg, 인덱스 2)
ret = zssc3230_nvm_write_24bit(2, 0x123456, timeout_ms);
if (ret == HAL_OK) printf("Tcg write (24-bit) succeeded\n");
else printf("Tcg write failed\n");
int32_t coeff_value;
ret = zssc3230_nvm_read_24bit(2, &coeff_value, timeout_ms);
if (ret == HAL_OK) printf("Tcg (24-bit) = 0x%06X\n", (uint32_t)coeff_value);
else printf("Tcg read failed\n");
// 7. 원시 온도 측정 (A6HEX)
ret = zssc3230_raw_temp_measure(&temp_data, timeout_ms);
if (ret == HAL_OK) printf("Raw temp data: 0x%06X\n", temp_data);
else printf("Raw temp measurement failed\n");
// 8. 오버샘플링 측정 (ACHEX)
ret = zssc3230_oversample_measure(0xAC, &sensor_data, &temp_data, timeout_ms);
if (ret == HAL_OK) printf("Oversample-2 sensor: 0x%06X, temp: 0x%06X\n", sensor_data, temp_data);
else printf("Oversample-2 measurement failed\n");
// 9. 주기적 측정 모드 (ABHEX)
ret = zssc3230_start_cyclic_mode(&sensor_data, &temp_data, timeout_ms);
if (ret == HAL_OK) printf("Cyclic mode started, sensor: 0x%06X, temp: 0x%06X\n", sensor_data, temp_data);
else printf("Cyclic mode failed\n");
// 10. PDM 정지 (B4HEX)
ret = zssc3230_stop_pdm(timeout_ms);
if (ret == HAL_OK) printf("PDM stopped\n");
else printf("PDM stop failed\n");
// 11. 브로큰 칩 테스트 (B0HEX)
ret = zssc3230_broken_chip_test(&result, timeout_ms);
if (ret == HAL_OK) printf("Broken chip test: %s (0x%04X)\n", result ? "Fail" : "Pass", result);
else printf("Broken chip test failed\n");
// 12. 슬립 모드 (A8HEX)
ret = zssc3230_start_sleep(timeout_ms);
if (ret == HAL_OK) printf("Sleep mode entered\n");
else printf("Sleep mode failed\n");
// 13. 소프트 리셋 (FXHEX)
ret = zssc3230_soft_reset(timeout_ms);
if (ret == HAL_OK) printf("Soft reset succeeded\n");
else printf("Soft reset failed\n");
}
반응형
'아날로그회로(Analog Circuit) > ADC관련' 카테고리의 다른 글
[ZSC31050] I²C 인터페이스 설정 및 데이터 처리 코드 구현 (0) | 2025.08.16 |
---|---|
[ZSSC3230] 보정 절차 및 Calibration Math 분석 (1) | 2025.08.15 |
[ZSSC3230] 센서 신호 컨디셔너(SSC) STM32을 사용한 I2C 코드 구현 (0) | 2025.08.15 |
[ZSSC3230] 원시 센서(Raw Sensor) 측정 설정 절차 (0) | 2025.08.15 |
[ZSSC3230]정전용량 센서 신호 컨디셔너 요약 (1) | 2025.08.14 |
[AD2S1210] Resolver-to-Digital Converter with STM32G474 SPI Driver (0) | 2025.08.14 |
[AD7747]정전용량-디지털 변환기 디바이스 드라이버 코드를 STM32용으로 구현 (Guide to implementing AD7747 Capacitance-to-Digital Converter driver for STM32 microcontroller) (0) | 2025.08.14 |
[ZSSC3123]Command List and Encodings 상세 분석 (0) | 2025.08.13 |