Skip to content

Commit 6d0de54

Browse files
committed
[bsp][n32] n32hxxx: add the H47x_48x/H49x timer support and cover the BSP with ci-attach
The N32H47x_48x and N32H49x series share drv_tim.c with N32H7xx, but only the H7xx branch was ever implemented, so clock timer, LPTIM, PWM and pulse encoder built to nothing on n32h487zgl7-evb and n32h497zgl7-evb. This adds those branches and gives all three boards a ci-attach entry set that actually compiles what the drivers claim to support. Drivers - drv_tim.c gains the H47x_48x/H49x clock-source and clock-enable branches, the ATIM/GTIM/BTIM instance tables and n32_tim_clock_freq_get(), which reads the real PCLK/HCLK/SYSCLK back from RCC rather than assuming one. ATIMCLKSEL is inverted between the two families and is handled as such. - drv_lptim.c derives its tick from the real LSI value instead of a hard-coded one, unlocks the backup domain before touching RCC, latches the prescaler, and returns -RT_EINVAL rather than clamping a bad rate. - drv_pwm.c and drv_pulse_encoder.c are extended to the H47x_48x/H49x instances; the H7xx encoder's update event is cleared through TIM_EnableUpdateEvt() because that family has no TIM_ConfigUpdateEvt(). - config/{h47x_48x,h49x}/{tim,pwm,pulse_encoder,lptim}_config.h are new and enumerate the instances each series has, for the existing drivers to read. Kconfig The timer menus move out of libraries/N32_Drivers/drivers/Kconfig into each board's board/Kconfig, so that a board's peripheral options live with the board and the shared driver Kconfig stays series-neutral. All three copies enforce the mutual exclusion drv_pulse_encoder.c documents (a timer instance enabled for both clock timer and pulse encoder collides at link time on the shared ISR symbol); N32H7xx's menus had none at all and are brought in line. ci-attach 51 entries across the three boards (17/16/18), including NAND at both bus widths and a large-geometry NAND entry. That last one exists because drv_nand.c picks the row-address cycle count from pages_per_block * block_count: 2 cycles up to 65536 pages, 3 up to 16777216, else 4. Every other NAND entry takes the Kconfig default 64 * 1024 = 65536, which lands exactly on the first boundary, so the >= 3 and >= 4 arms were compiled by nothing at all - it takes a geometry past the 24-bit row width to reach the top rung. The entry pins that geometry to arm them; it is not a claim about the part on the board. Fixes carried in the same series - drv_nand.c emitted its third row-address byte under `== 3`, so a 4-cycle part would set the count to 4 and then match no emitter, dropping the high row-address bytes outright. The three guards are now >= 3 with the >= 4 byte added. row_addr is uint32_t at all three sites. - timer_ctrl() wrote the prescaler straight to a 16-bit PSC field. TIM_ConfigPrescaler() neither masks nor validates, so any freq below timer_clock/65537 was truncated and the timer ran at an unrelated rate while timer->freq still recorded the requested one. That window is reachable: both boards clock timers at 240 MHz, so the honest floor is ~3662 Hz while tim_config.h sets minfreq = 3000 and only [minfreq, maxfreq] is checked - 3000 Hz lands in PSC as 14463, about 16.6 kHz. Division by zero and any prescaler above 0xFFFF now return -RT_EINVAL. The H7xx branch had the identical truncation, so the same two guards are applied there too. - n32_tim_enable_clock() closed each new branch with RT_ASSERT(RT_TRUE). With RT_DEBUGING_ASSERT on, RT_ASSERT() expands to `if (!(EX)) rt_assert_handler(...)`, so that guard could never fire: a timer matching none of the branch's instances enabled no clock at all and the caller went on to touch an unclocked peripheral's registers. All three branches are now RT_FALSE. The H7xx guard cannot fire today - every instance its config header can hand out is already in that branch's ladder - so fixing it arms the guard against a future instance added to the table but not the ladder, rather than changing any existing configuration. - h497's sdram entry asked for BSP_SDRAM_SIZE=32 while sdram_port.h documents the part as 8 MB and board/Kconfig declares `range 8 256` with `default 8`; the 32 came from h760, whose own default happens to be 32. - drv_hard_i2c.c had no init path at all for H47x_48x/H49x, leaving those series with an unconfigured controller; the SCL rate now travels in the config struct instead of being assumed. - drv_qspi.c and drv_spi.c indexed buffers longer than 65535 bytes with 16-bit counters, which wraps at exactly 65536. - n32eth_cfg.h is added because the H7xx and H49x SDKs' eth.h include it but no package in the tree ships it. It probes for the series headers because the SDK includes it before rtconfig.h can define SOC_SERIES_*, with a part-macro fallback for ARM Compiler 5, which has no __has_include() and is what every Keil project in this BSP uses. - n32h487zgl7-evb now builds with its real 8 MHz crystal; left at the header's 16 MHz default, RCC_GetClocksFreqValue() reports every clock at twice its value and the timer prescalers come out twice too large. - n32h760zil7-stb's timer menus had no mutual exclusion at all, so a timer instance could be enabled as both a clock timer and a pulse encoder; 24 ISR symbols are defined by both drivers under those two guards, so only the linker would have caught it. Its 14 PWM menus and its 14 encoder entries now carry the same guard as the two new boards', using the PWMn == PULSE_ENCODERN == instance n mapping that config/h7xx's pulse_encoder_config.h establishes. On the PWM side that guard is a resource guard, not a link one: drv_pwm.c defines no ISRs. - the same board's LPTIM menu selected RT_USING_LPTIMER, which is not declared anywhere in the tree. A select of an undeclared symbol is an implicit symbol and raises no diagnostic, so the line had never done anything; it is dropped, as the two new menus already do. Three stm32 boards still carry it and are left alone. The H49x LPTIM EXTI lines needed the user manual rather than the SDK to settle, and the manual sides with the driver: N32H49x maps EXTI line 21 to the LPTIM1 wakeup event and line 22 to LPTIM2, which is what n32_lptim_get_exti_line() returns. The headers disagree only because n32h49x_exti.h's EXTI_LINE16..24 block is a verbatim copy of n32h47x_48x_exti.h's - that one carries on past line 24 and names 25/26 as the LPTIM events with 21/22 as COMP1/COMP4 - while the H49x series has no comparator in its SDK at all, so its copy of that text is stale. The driver states the reasoning in a comment rather than the bare value. The H49x timer clock-source bits needed the user manual rather than the SDK to settle. For GTIM8/9/10 (RCC_CFG2 bit 27) h49x names the cleared case RCC_GTIM_CLKSRC_SYSCLKDIV where h47x_48x names it RCC_GTIM_CLKSRC_PCLK, and the manual sides with the driver's arithmetic: bit 27 selects SYSCLK, or SYSCLK/(APB2 prescaler / 2) when that prescaler is engaged - the same rule the driver writes from the HCLK side as PCLK2 doubled whenever PCLK2 is below HCLK. Both boards hold AHBPRES at RCC_SYSCLK_DIV1, so HCLK and SYSCLK are the same 240 MHz and either spelling gives the same number. The driver tests the raw bit and not either family's constant, so the naming difference never reaches the code. The same chapter confirms bit 28's inversion, which the ATIM branches already follow. Verified: all three boards build from scratch under --strict (gcc -Werror) with zero diagnostics; all 51 ci-attach entries build clean; the three series were rebuilt after the assert fix, each through the --attach path that compiles its branch (devices.timer on all three boards - h760's default leaves BSP_USING_CLOCK_TIMER off, so drv_tim.c is not compiled by it at all), rebuilt again after the Kconfig guards, whose effect was checked by loading the tree with kconfiglib and confirming that clock-timer ATIM1 with pulse encoder1 goes from satisfiable to unsatisfiable while a non-colliding pair is left alone); the NAND row-address arms were confirmed compiled by injecting #error markers and rebuilding through the real --attach path; each board's committed .config and rtconfig.h reproduce byte-for-byte from a fresh defconfig; and the CI clang-format gate reports 0 files / 0 lines.
1 parent 69451d1 commit 6d0de54

39 files changed

Lines changed: 3956 additions & 105 deletions

‎bsp/README.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,8 +334,8 @@ This document is based on the RT-Thread mainline repository and categorizes the
334334
| [n32l43xrl-stb](n32/n32gxx_lxx/n32l43xrl-stb) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | - | - | - | - | - | - | - | - |
335335
| [n32wb45xl-evb](n32/n32gxx_lxx/n32wb45xl-evb) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | - | - | - | - | - | - | - | - |
336336
| [n32h760zil7-stb](n32/n32hxxx/n32h760zil7-stb) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
337-
| [n32h497zgl7-evb](n32/n32hxxx/n32h497zgl7-evb) | ✅ | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ | ✅ | - | - | - | ✅ | ✅ | ✅ | ✅ | - | ✅ |
338-
| [n32h487zgl7-evb](n32/n32hxxx/n32h487zgl7-evb) | ✅ | ✅ | ✅ | ✅ | ✅ | - | ✅ | ✅ | ✅ | ✅ | - | - | - | ✅ | ✅ | ✅ | - | - | ✅ |
337+
| [n32h497zgl7-evb](n32/n32hxxx/n32h497zgl7-evb) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | ✅ |
338+
| [n32h487zgl7-evb](n32/n32hxxx/n32h487zgl7-evb) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | - | - | ✅ |
339339

340340

341341
#### 🟡 NRF5x

‎bsp/n32/n32hxxx/libraries/N32_Drivers/drivers/SConscript‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ if GetDepend(['RT_USING_SERIAL']):
1717
else:
1818
src += ['drv_usart.c']
1919

20-
if GetDepend(['BSP_USING_CLOCK_TIMER']):
20+
if GetDepend(['BSP_USING_CLOCK_TIMER']) or GetDepend(['BSP_USING_PWM']) or GetDepend(['BSP_USING_PULSE_ENCODER']):
2121
src += ['drv_tim.c']
2222

2323
if GetDepend(['BSP_USING_PWM']):
24-
src += ['drv_pwm.c', 'drv_tim.c']
24+
src += ['drv_pwm.c']
2525

2626
if GetDepend(['RT_USING_SPI']):
2727
src += ['drv_spi.c']
@@ -85,7 +85,7 @@ if GetDepend(['BSP_USING_SDIO']):
8585
src += ['drv_sdio.c']
8686

8787
if GetDepend(['BSP_USING_PULSE_ENCODER']):
88-
src += ['drv_pulse_encoder.c', 'drv_tim.c']
88+
src += ['drv_pulse_encoder.c']
8989

9090

9191
path += [os.path.join(cwd, 'config')]

‎bsp/n32/n32hxxx/libraries/N32_Drivers/drivers/config/h47x_48x/i2c_hard_config.h‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ extern "C" {
2323
{ \
2424
.name = "hwi2c1", \
2525
.Instance = I2C1, \
26+
.timing = 100000, \
2627
.timeout = 0x1000, \
2728
.evirq_type = I2C1_EV_IRQn, \
2829
.erirq_type = I2C1_ER_IRQn, \
@@ -68,6 +69,7 @@ extern "C" {
6869
{ \
6970
.name = "hwi2c2", \
7071
.Instance = I2C2, \
72+
.timing = 100000, \
7173
.timeout = 0x1000, \
7274
.evirq_type = I2C2_EV_IRQn, \
7375
.erirq_type = I2C2_ER_IRQn, \
@@ -113,6 +115,7 @@ extern "C" {
113115
{ \
114116
.name = "hwi2c3", \
115117
.Instance = I2C3, \
118+
.timing = 100000, \
116119
.timeout = 0x1000, \
117120
.evirq_type = I2C3_EV_IRQn, \
118121
.erirq_type = I2C3_ER_IRQn, \
@@ -158,6 +161,7 @@ extern "C" {
158161
{ \
159162
.name = "hwi2c4", \
160163
.Instance = I2C4, \
164+
.timing = 100000, \
161165
.timeout = 0x1000, \
162166
.evirq_type = I2C4_EV_IRQn, \
163167
.erirq_type = I2C4_ER_IRQn, \
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright (c) 2006-2025, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2026-08-19 ox-horse first version
9+
*/
10+
11+
#ifndef __LPTIM_CONFIG_H__
12+
#define __LPTIM_CONFIG_H__
13+
14+
#include <rtthread.h>
15+
16+
#ifdef __cplusplus
17+
extern "C" {
18+
#endif
19+
20+
/* LSI through a fixed DIV32, both set in drv_lptim.c's timer_init(), so the
21+
* tick rate is LSI_VALUE / 32 = 32000 / 32 = 1000 Hz and cannot be
22+
* programmed -- hence a single-point range. clock_timer.c scales timeouts by
23+
* timer->freq, which it takes from here, so a wrong value scales every one.
24+
*/
25+
#ifndef LPTIM_DEV_INFO_CONFIG
26+
#define LPTIM_DEV_INFO_CONFIG \
27+
{ \
28+
.maxfreq = 1000, \
29+
.minfreq = 1000, \
30+
.maxcnt = 0xFFFF, \
31+
.cntmode = CLOCK_TIMER_CNTMODE_UP, \
32+
}
33+
#endif /* LPTIM_DEV_INFO_CONFIG */
34+
35+
#ifdef BSP_USING_LPTIM1
36+
#ifndef LPTIM1_CONFIG
37+
#define LPTIM1_CONFIG \
38+
{ \
39+
.timer = LPTIM1, \
40+
.tim_irqn = LPTIM1_WKUP_IRQn, \
41+
.name = "lptim1", \
42+
}
43+
#endif /* LPTIM1_CONFIG */
44+
#endif /* BSP_USING_LPTIM1 */
45+
46+
#ifdef BSP_USING_LPTIM2
47+
#ifndef LPTIM2_CONFIG
48+
#define LPTIM2_CONFIG \
49+
{ \
50+
.timer = LPTIM2, \
51+
.tim_irqn = LPTIM2_WKUP_IRQn, \
52+
.name = "lptim2", \
53+
}
54+
#endif /* LPTIM2_CONFIG */
55+
#endif /* BSP_USING_LPTIM2 */
56+
57+
#ifdef __cplusplus
58+
}
59+
#endif
60+
61+
#endif /* __LPTIM_CONFIG_H__ */
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*
2+
* Copyright (c) 2006-2025, RT-Thread Development Team
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*
6+
* Change Logs:
7+
* Date Author Notes
8+
* 2026-08-19 ox-horse first version
9+
*/
10+
11+
#ifndef __PULSE_ENCODER_CONFIG_H__
12+
#define __PULSE_ENCODER_CONFIG_H__
13+
14+
#include <rtthread.h>
15+
16+
#ifdef __cplusplus
17+
extern "C" {
18+
#endif
19+
20+
#ifdef BSP_USING_PULSE_ENCODER1
21+
#ifndef PULSE_ENCODER1_CONFIG
22+
#define PULSE_ENCODER1_CONFIG \
23+
{ \
24+
.timer = ATIM1, \
25+
.tim_irqn = ATIM1_UP_IRQn, \
26+
.name = "pulse1", \
27+
}
28+
#endif /* PULSE_ENCODER1_CONFIG */
29+
#endif /* BSP_USING_PULSE_ENCODER1 */
30+
31+
#ifdef BSP_USING_PULSE_ENCODER2
32+
#ifndef PULSE_ENCODER2_CONFIG
33+
#define PULSE_ENCODER2_CONFIG \
34+
{ \
35+
.timer = ATIM2, \
36+
.tim_irqn = ATIM2_UP_IRQn, \
37+
.name = "pulse2", \
38+
}
39+
#endif /* PULSE_ENCODER2_CONFIG */
40+
#endif /* BSP_USING_PULSE_ENCODER2 */
41+
42+
#ifdef BSP_USING_PULSE_ENCODER3
43+
#ifndef PULSE_ENCODER3_CONFIG
44+
#define PULSE_ENCODER3_CONFIG \
45+
{ \
46+
.timer = ATIM3, \
47+
.tim_irqn = ATIM3_UP_IRQn, \
48+
.name = "pulse3", \
49+
}
50+
#endif /* PULSE_ENCODER3_CONFIG */
51+
#endif /* BSP_USING_PULSE_ENCODER3 */
52+
53+
#ifdef BSP_USING_PULSE_ENCODER5
54+
#ifndef PULSE_ENCODER5_CONFIG
55+
#define PULSE_ENCODER5_CONFIG \
56+
{ \
57+
.timer = GTIM1, \
58+
.tim_irqn = GTIM1_IRQn, \
59+
.name = "pulse5", \
60+
}
61+
#endif /* PULSE_ENCODER5_CONFIG */
62+
#endif /* BSP_USING_PULSE_ENCODER5 */
63+
64+
#ifdef BSP_USING_PULSE_ENCODER6
65+
#ifndef PULSE_ENCODER6_CONFIG
66+
#define PULSE_ENCODER6_CONFIG \
67+
{ \
68+
.timer = GTIM2, \
69+
.tim_irqn = GTIM2_IRQn, \
70+
.name = "pulse6", \
71+
}
72+
#endif /* PULSE_ENCODER6_CONFIG */
73+
#endif /* BSP_USING_PULSE_ENCODER6 */
74+
75+
#ifdef BSP_USING_PULSE_ENCODER7
76+
#ifndef PULSE_ENCODER7_CONFIG
77+
#define PULSE_ENCODER7_CONFIG \
78+
{ \
79+
.timer = GTIM3, \
80+
.tim_irqn = GTIM3_IRQn, \
81+
.name = "pulse7", \
82+
}
83+
#endif /* PULSE_ENCODER7_CONFIG */
84+
#endif /* BSP_USING_PULSE_ENCODER7 */
85+
86+
#ifdef BSP_USING_PULSE_ENCODER8
87+
#ifndef PULSE_ENCODER8_CONFIG
88+
#define PULSE_ENCODER8_CONFIG \
89+
{ \
90+
.timer = GTIM4, \
91+
.tim_irqn = GTIM4_IRQn, \
92+
.name = "pulse8", \
93+
}
94+
#endif /* PULSE_ENCODER8_CONFIG */
95+
#endif /* BSP_USING_PULSE_ENCODER8 */
96+
97+
#ifdef BSP_USING_PULSE_ENCODER9
98+
#ifndef PULSE_ENCODER9_CONFIG
99+
#define PULSE_ENCODER9_CONFIG \
100+
{ \
101+
.timer = GTIM5, \
102+
.tim_irqn = GTIM5_IRQn, \
103+
.name = "pulse9", \
104+
}
105+
#endif /* PULSE_ENCODER9_CONFIG */
106+
#endif /* BSP_USING_PULSE_ENCODER9 */
107+
108+
#ifdef BSP_USING_PULSE_ENCODER10
109+
#ifndef PULSE_ENCODER10_CONFIG
110+
#define PULSE_ENCODER10_CONFIG \
111+
{ \
112+
.timer = GTIM6, \
113+
.tim_irqn = GTIM6_IRQn, \
114+
.name = "pulse10", \
115+
}
116+
#endif /* PULSE_ENCODER10_CONFIG */
117+
#endif /* BSP_USING_PULSE_ENCODER10 */
118+
119+
#ifdef BSP_USING_PULSE_ENCODER11
120+
#ifndef PULSE_ENCODER11_CONFIG
121+
#define PULSE_ENCODER11_CONFIG \
122+
{ \
123+
.timer = GTIM7, \
124+
.tim_irqn = GTIM7_IRQn, \
125+
.name = "pulse11", \
126+
}
127+
#endif /* PULSE_ENCODER11_CONFIG */
128+
#endif /* BSP_USING_PULSE_ENCODER11 */
129+
130+
#ifdef BSP_USING_PULSE_ENCODER12
131+
#ifndef PULSE_ENCODER12_CONFIG
132+
#define PULSE_ENCODER12_CONFIG \
133+
{ \
134+
.timer = GTIM8, \
135+
.tim_irqn = GTIM8_IRQn, \
136+
.name = "pulse12", \
137+
}
138+
#endif /* PULSE_ENCODER12_CONFIG */
139+
#endif /* BSP_USING_PULSE_ENCODER12 */
140+
141+
#ifdef BSP_USING_PULSE_ENCODER13
142+
#ifndef PULSE_ENCODER13_CONFIG
143+
#define PULSE_ENCODER13_CONFIG \
144+
{ \
145+
.timer = GTIM9, \
146+
.tim_irqn = GTIM9_IRQn, \
147+
.name = "pulse13", \
148+
}
149+
#endif /* PULSE_ENCODER13_CONFIG */
150+
#endif /* BSP_USING_PULSE_ENCODER13 */
151+
152+
#ifdef BSP_USING_PULSE_ENCODER14
153+
#ifndef PULSE_ENCODER14_CONFIG
154+
#define PULSE_ENCODER14_CONFIG \
155+
{ \
156+
.timer = GTIM10, \
157+
.tim_irqn = GTIM10_IRQn, \
158+
.name = "pulse14", \
159+
}
160+
#endif /* PULSE_ENCODER14_CONFIG */
161+
#endif /* BSP_USING_PULSE_ENCODER14 */
162+
163+
#ifdef __cplusplus
164+
}
165+
#endif
166+
167+
#endif /* __PULSE_ENCODER_CONFIG_H__ */

0 commit comments

Comments
 (0)