mirror of
https://github.com/ArduPilot/ardupilot.git
synced 2026-10-06 19:00:27 +08:00
AP_HAL_ChibiOS: support I2Cv4 single DMA channel
The ChibiOS I2Cv4 LLD (used on STM32G0/G4/C0/U0/U3/H5/L4+) uses a single DMA channel per I2C peripheral, shared between TX and RX, configured via STM32_I2C_I2Cx_DMA_CHANNEL. The previous code emitted the separate STM32_I2C_I2Cx_RX/TX_DMA_STREAM defines used by I2Cv2/I2Cv3, which no longer satisfy the I2Cv4 driver. Detect I2Cv4 MCUs from CHIBIOS_PLATFORM_MK, allocate a single DMA channel per I2C peripheral in dma_resolver.py (no _RX/_TX split), and generate HAL_I2Cn_CONFIG entries that feed the single channel into the shared DMA slot with SHARED_DMA_NONE as the partner. Also replace the unconditional STM32_I2C_USE_I2Cn TRUE lines in stm32g4_mcuconf.h with #ifndef-guarded defaults to FALSE, so boards only enable the I2C peripherals their hwdef actually uses. Without this, the I2Cv4 driver demanded DMA channels for every I2C peripheral on every G4 board regardless of pin usage.
This commit is contained in:
@@ -232,10 +232,18 @@
|
||||
/*
|
||||
* I2C driver system settings.
|
||||
*/
|
||||
#define STM32_I2C_USE_I2C1 TRUE
|
||||
#define STM32_I2C_USE_I2C2 TRUE
|
||||
#define STM32_I2C_USE_I2C3 TRUE
|
||||
#define STM32_I2C_USE_I2C4 TRUE
|
||||
#ifndef STM32_I2C_USE_I2C1
|
||||
#define STM32_I2C_USE_I2C1 FALSE
|
||||
#endif
|
||||
#ifndef STM32_I2C_USE_I2C2
|
||||
#define STM32_I2C_USE_I2C2 FALSE
|
||||
#endif
|
||||
#ifndef STM32_I2C_USE_I2C3
|
||||
#define STM32_I2C_USE_I2C3 FALSE
|
||||
#endif
|
||||
#ifndef STM32_I2C_USE_I2C4
|
||||
#define STM32_I2C_USE_I2C4 FALSE
|
||||
#endif
|
||||
#define STM32_I2C_BUSY_TIMEOUT 50
|
||||
#define STM32_IRQ_I2C1_PRIORITY 5
|
||||
#define STM32_IRQ_I2C2_PRIORITY 5
|
||||
|
||||
@@ -665,6 +665,24 @@ class ChibiOSHWDef(hwdef.HWDef):
|
||||
return None
|
||||
return lib.mcu[name]
|
||||
|
||||
def mcu_uses_I2Cv4(self):
|
||||
'''return True if this MCU uses the ChibiOS I2Cv4 LLD driver, which
|
||||
uses a single DMA channel per I2C peripheral (shared between TX and
|
||||
RX) rather than separate RX and TX streams'''
|
||||
lib = self.get_mcu_lib(self.mcu_type)
|
||||
platform_mk = getattr(lib, 'build', {}).get('CHIBIOS_PLATFORM_MK', '')
|
||||
# ChibiOS platform directories whose platform.mk pulls in LLD/I2Cv4
|
||||
i2cv4_platforms = (
|
||||
'STM32G0xx/',
|
||||
'STM32G4xx/',
|
||||
'STM32C0xx/',
|
||||
'STM32U0xx/',
|
||||
'STM32U3xx/',
|
||||
'STM32H5xx/',
|
||||
'STM32L4xx+/',
|
||||
)
|
||||
return any(p in platform_mk for p in i2cv4_platforms)
|
||||
|
||||
def get_ram_reserve_start(self):
|
||||
'''get amount of memory to reserve for bootloader comms and the address if non-zero'''
|
||||
ram_reserve_start = self.get_config('RAM_RESERVE_START', default=0, type=int)
|
||||
@@ -1935,6 +1953,7 @@ INCLUDE common.ld
|
||||
devlist = []
|
||||
|
||||
# write out config structures
|
||||
uses_i2cv4 = self.mcu_uses_I2Cv4()
|
||||
for dev in i2c_list:
|
||||
if not dev.startswith('I2C') or dev[3] not in "1234":
|
||||
self.error("Bad I2C_ORDER element %s" % dev)
|
||||
@@ -1942,14 +1961,26 @@ INCLUDE common.ld
|
||||
devlist.append('HAL_I2C%u_CONFIG' % n)
|
||||
sda_line = self.make_line('I2C%u_SDA' % n)
|
||||
scl_line = self.make_line('I2C%u_SCL' % n)
|
||||
f.write('''
|
||||
if uses_i2cv4:
|
||||
# I2Cv4 (STM32G0/G4/C0/U0/U3/H5/L4+) uses a single DMA
|
||||
# channel for both TX and RX on each I2C peripheral
|
||||
f.write('''
|
||||
#if defined(STM32_I2C_I2C%u_DMA_CHANNEL)
|
||||
#define HAL_I2C%u_CONFIG { &I2CD%u, %u, STM32_I2C_I2C%u_DMA_CHANNEL, SHARED_DMA_NONE, %s, %s }
|
||||
#else
|
||||
#define HAL_I2C%u_CONFIG { &I2CD%u, %u, SHARED_DMA_NONE, SHARED_DMA_NONE, %s, %s }
|
||||
#endif
|
||||
'''
|
||||
% (n, n, n, n, n, scl_line, sda_line, n, n, n, scl_line, sda_line))
|
||||
else:
|
||||
f.write('''
|
||||
#if defined(STM32_I2C_I2C%u_RX_DMA_STREAM) && defined(STM32_I2C_I2C%u_TX_DMA_STREAM)
|
||||
#define HAL_I2C%u_CONFIG { &I2CD%u, %u, STM32_I2C_I2C%u_RX_DMA_STREAM, STM32_I2C_I2C%u_TX_DMA_STREAM, %s, %s }
|
||||
#else
|
||||
#define HAL_I2C%u_CONFIG { &I2CD%u, %u, SHARED_DMA_NONE, SHARED_DMA_NONE, %s, %s }
|
||||
#endif
|
||||
'''
|
||||
% (n, n, n, n, n, n, n, scl_line, sda_line, n, n, n, scl_line, sda_line))
|
||||
% (n, n, n, n, n, n, n, scl_line, sda_line, n, n, n, scl_line, sda_line))
|
||||
f.write('\n')
|
||||
self.write_device_table(f, "i2c devices", "HAL_I2C_DEVICE_LIST", devlist)
|
||||
|
||||
@@ -2648,6 +2679,13 @@ Please run: Tools/scripts/build_bootloaders.py %s
|
||||
continue
|
||||
for prefix in prefixes:
|
||||
if type.startswith(prefix):
|
||||
if prefix == 'I2C' and self.mcu_uses_I2Cv4():
|
||||
# I2Cv4 uses a single DMA channel per I2C peripheral
|
||||
# shared between TX and RX, so request DMA using the
|
||||
# plain peripheral name (no _RX/_TX suffix)
|
||||
if type not in peripherals:
|
||||
peripherals.append(type)
|
||||
break
|
||||
ptx = type + "_TX"
|
||||
prx = type + "_RX"
|
||||
if prefix in ['SPI', 'I2C']:
|
||||
|
||||
@@ -471,9 +471,17 @@ def write_dma_header(f, peripheral_list, mcu_type, dma_exclude=[],
|
||||
shared = ' // shared %s' % ','.join(stream_assign[stream])
|
||||
if stream[0] in [1,2]:
|
||||
shared_set.add("(1U<<STM32_DMA_STREAM_ID(%u,%u))" % (stream[0],stream[1]))
|
||||
# Plain I2C key (no _RX/_TX suffix) is used for the ChibiOS I2Cv4 LLD
|
||||
# which takes a single DMA channel per peripheral via
|
||||
# STM32_I2C_I2Cx_DMA_CHANNEL, and handles DMAMUX request source
|
||||
# selection internally.
|
||||
is_i2cv4 = (key.startswith('I2C') and
|
||||
not key.endswith('_RX') and not key.endswith('_TX'))
|
||||
stream_suffix = 'CHANNEL' if is_i2cv4 else 'STREAM'
|
||||
if curr_dict[key] == "STM32_DMA_STREAM_ID_ANY":
|
||||
f.write("#define %-30s STM32_DMA_STREAM_ID_ANY\n" % (chibios_dma_define_name(key)+'STREAM'))
|
||||
f.write("#define %-30s %s\n" % (chibios_dma_define_name(key)+'CHAN', dmamux_channel(key)))
|
||||
f.write("#define %-30s STM32_DMA_STREAM_ID_ANY\n" % (chibios_dma_define_name(key)+stream_suffix))
|
||||
if not is_i2cv4:
|
||||
f.write("#define %-30s %s\n" % (chibios_dma_define_name(key)+'CHAN', dmamux_channel(key)))
|
||||
continue
|
||||
else:
|
||||
dma_controller = curr_dict[key][0]
|
||||
@@ -484,7 +492,7 @@ def write_dma_header(f, peripheral_list, mcu_type, dma_exclude=[],
|
||||
continue
|
||||
else:
|
||||
f.write("#define %-30s STM32_DMA_STREAM_ID(%u, %u)%s\n" %
|
||||
(chibios_dma_define_name(key)+'STREAM', dma_controller,
|
||||
(chibios_dma_define_name(key)+stream_suffix, dma_controller,
|
||||
curr_dict[key][1], shared))
|
||||
if have_DMAMUX and "_UP" in key:
|
||||
# share the dma with rest of the _CH ports
|
||||
@@ -495,6 +503,10 @@ def write_dma_header(f, peripheral_list, mcu_type, dma_exclude=[],
|
||||
f.write("#define %-30s STM32_DMA_STREAM_ID(%u, %u)%s\n" %
|
||||
(chibios_dma_define_name(chkey)+'STREAM', dma_controller,
|
||||
curr_dict[key][1], shared))
|
||||
if is_i2cv4:
|
||||
# I2Cv4 does not need a separate CHAN define; the LLD selects
|
||||
# the DMAMUX request source (STM32_DMAMUX1_I2Cx_TX/RX) itself
|
||||
continue
|
||||
for streamchan in sorted(dma_map[key]):
|
||||
if stream == (streamchan[0], streamchan[1]):
|
||||
if have_DMAMUX:
|
||||
@@ -510,7 +522,7 @@ def write_dma_header(f, peripheral_list, mcu_type, dma_exclude=[],
|
||||
if chkey not in timer_ch_periph:
|
||||
continue
|
||||
f.write("#define %-30s %s\n" %
|
||||
(chibios_dma_define_name(chkey)+'CHAN',
|
||||
(chibios_dma_define_name(chkey)+'CHAN',
|
||||
chan.replace('_UP', '_CH{}'.format(ch))))
|
||||
break
|
||||
|
||||
|
||||
Reference in New Issue
Block a user