update firmware
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* main.c 안의 카운팅 로직(load_counts / drive / HAL_TIM_PeriodElapsedCallback)을
|
||||
* 그대로 옮겨와 PC에서 돌려보는 검증용 프로그램.
|
||||
* MCU/HAL 없이도 "틱이 몇 번 지나면 LED가 몇 번 깜박이는가"가 설계값과
|
||||
* 정확히 일치하는지를 기계적으로 확인하기 위한 것.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define LED_MASK 0x01FFu
|
||||
#define N_POINTS 9
|
||||
#define COUNT_MIN 1
|
||||
#define COUNT_MAX 15
|
||||
#define TICKS_BURST 30
|
||||
#define TICKS_IDLE 10
|
||||
#define TICKS_CYCLE (TICKS_BURST + TICKS_IDLE)
|
||||
|
||||
static uint16_t tick = 0;
|
||||
static uint16_t cycle = 0;
|
||||
static uint8_t cnt[N_POINTS];
|
||||
|
||||
/* --- 실제 main.c와 동일한 로직 --- */
|
||||
static void load_counts(void)
|
||||
{
|
||||
for (uint8_t k = 0; k < N_POINTS; k++) {
|
||||
cnt[k] = (uint8_t)(((cycle + k) % COUNT_MAX) + COUNT_MIN);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t drive_bsrr(uint16_t bits)
|
||||
{
|
||||
/* 실제 GPIOC->BSRR 대신, 계산 결과만 반환 */
|
||||
return ((uint32_t)( bits & LED_MASK) << 16)
|
||||
| ((uint32_t)(~bits & LED_MASK));
|
||||
}
|
||||
|
||||
/* 검증용 상태: 각 지점의 "실제 관측된" 상승 에지(꺼짐->켜짐) 횟수 */
|
||||
static uint16_t rising_edges[N_POINTS];
|
||||
static uint16_t prev_bits = 0;
|
||||
|
||||
static void tick_step(void)
|
||||
{
|
||||
uint16_t bits = 0;
|
||||
|
||||
if (tick < TICKS_BURST && (tick & 1u) == 0u) {
|
||||
for (uint8_t k = 0; k < N_POINTS; k++) {
|
||||
if (tick < (uint16_t)cnt[k] * 2u) {
|
||||
bits |= (uint16_t)(1u << k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 검증: 상승 에지 카운트 (디코더가 세는 것과 동일한 방식) */
|
||||
for (uint8_t k = 0; k < N_POINTS; k++) {
|
||||
uint16_t m = (uint16_t)(1u << k);
|
||||
if ((bits & m) && !(prev_bits & m)) rising_edges[k]++;
|
||||
}
|
||||
prev_bits = bits;
|
||||
|
||||
(void)drive_bsrr(bits); /* 레지스터 계산이 죽지 않는지만 확인 */
|
||||
|
||||
if (++tick >= TICKS_CYCLE) {
|
||||
tick = 0;
|
||||
|
||||
printf("CYCLE=%u 목표:", cycle + 1);
|
||||
for (uint8_t k = 0; k < N_POINTS; k++) printf(" G%u=%2u", k + 1, cnt[k]);
|
||||
printf("\n 실측:");
|
||||
int all_match = 1;
|
||||
for (uint8_t k = 0; k < N_POINTS; k++) {
|
||||
printf(" G%u=%2u", k + 1, rising_edges[k]);
|
||||
if (rising_edges[k] != cnt[k]) all_match = 0;
|
||||
}
|
||||
printf(" [%s]\n", all_match ? "일치" : "!! 불일치 !!");
|
||||
|
||||
for (uint8_t k = 0; k < N_POINTS; k++) rising_edges[k] = 0;
|
||||
cycle++;
|
||||
load_counts();
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
load_counts();
|
||||
|
||||
printf("=== 사이클 하나가 정확히 40틱(8.0s)인지 확인 ===\n");
|
||||
uint16_t total_ticks = 0;
|
||||
uint16_t start_cycle = cycle;
|
||||
while (cycle == start_cycle) { tick_step(); total_ticks++; }
|
||||
printf("1 사이클 = %u 틱 (기대값 %u) -> %s\n\n",
|
||||
total_ticks, (unsigned)TICKS_CYCLE,
|
||||
total_ticks == TICKS_CYCLE ? "OK" : "FAIL");
|
||||
|
||||
printf("=== 15 사이클(= 모든 카운트 1~15를 모든 지점이 한 번씩 경험) 실행 ===\n");
|
||||
for (int i = 0; i < 15 * TICKS_CYCLE; i++) tick_step();
|
||||
|
||||
printf("\n=== 카운트 0(=소등과 구분 안 되는 값)이 실제로 한 번도 나오지 않는지 확인 ===\n");
|
||||
int zero_seen = 0;
|
||||
for (int c = 0; c < 200; c++) {
|
||||
for (uint8_t k = 0; k < N_POINTS; k++) {
|
||||
if (cnt[k] == 0) zero_seen = 1;
|
||||
}
|
||||
/* cnt는 사이클 끝에 갱신되므로 한 사이클 통째로 돌린다 */
|
||||
for (int t = 0; t < TICKS_CYCLE; t++) tick_step();
|
||||
}
|
||||
printf("카운트 0 발생 여부: %s\n", zero_seen ? "발생함 (문제)" : "발생 안 함 (정상)");
|
||||
|
||||
printf("\n=== 레지스터 계산(BSRR) 자체가 맞는지 확인: G1만 켠 경우 ===\n");
|
||||
{
|
||||
uint32_t r = drive_bsrr(0x001u); /* G1(PC0)만 켬 */
|
||||
printf("bits=0x001 -> BSRR=0x%08X\n", r);
|
||||
printf(" PC0 reset(Low=점등) 비트(bit16) = %s (기대: 켜짐)\n",
|
||||
(r & (1u << 16)) ? "켜짐" : "꺼짐");
|
||||
printf(" PC1 set(High=소등) 비트(bit1) = %s (기대: 켜짐, 즉 꺼짐 상태)\n",
|
||||
(r & (1u << 1)) ? "켜짐" : "꺼짐");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user