diff --git a/cmsis/device/rtos/include/mbed_boot.h b/cmsis/device/rtos/include/mbed_boot.h index 6594512543b..af10f4d2ec2 100644 --- a/cmsis/device/rtos/include/mbed_boot.h +++ b/cmsis/device/rtos/include/mbed_boot.h @@ -19,6 +19,8 @@ #include "mbed_toolchain.h" +#include + #ifdef __cplusplus extern "C" { #endif diff --git a/hal/include/hal/pwmout_api.h b/hal/include/hal/pwmout_api.h index dc8fd84182e..3747cb70615 100644 --- a/hal/include/hal/pwmout_api.h +++ b/hal/include/hal/pwmout_api.h @@ -42,7 +42,7 @@ typedef struct pwmout_s pwmout_t; * * ::pwmout_write sets the output duty-cycle in range <0.0f, 1.0f> * * ::pwmout_read returns the current float-point output duty-cycle in range <0.0f, 1.0f> * * ::pwmout_period sets the PWM period specified in seconds, keeping the duty cycle the same - * * ::pwmout_period_ms sets the PWM period specified in miliseconds, keeping the duty cycle the same + * * ::pwmout_period_ms sets the PWM period specified in milliseconds, keeping the duty cycle the same * * ::pwmout_period_us sets the PWM period specified in microseconds, keeping the duty cycle the same * * ::pwmout_read_period_us reads the PWM period specified in microseconds * * ::pwmout_pulsewidth sets the PWM pulsewidth specified in seconds, keeping the period the same @@ -84,7 +84,11 @@ void pwmout_init_direct(pwmout_t *obj, const PinMap *pinmap); */ void pwmout_init(pwmout_t *obj, PinName pin); -/** Deinitialize the pwmout object +/** + * @brief Deinitialize the pwmout object + * + * After this function is called, the PWM output must stop generating edges. + * The logic level is not specified -- it may be left high, low, or tristated. * * @param obj The pwmout object */ diff --git a/hal/include/hal/spi_api.h b/hal/include/hal/spi_api.h index 90e836f52ab..5673cead694 100644 --- a/hal/include/hal/spi_api.h +++ b/hal/include/hal/spi_api.h @@ -276,11 +276,15 @@ int spi_master_write(spi_t *obj, int value); * * The total number of bytes sent and received will be the maximum of * tx_length and rx_length. The bytes written will be padded with the - * value 0xff. + * write fill value. * * Note: Even if the word size / bits per frame is not 8, \c rx_length and \c tx_length * still give lengths in bytes of input data, not numbers of words. * + * Note: If \c tx_rx_buffers_equal_length is true in the capabilities structure, then either \c rx_length and \c tx_length + * must be the same, or one of them will be zero. If this is not the case than the HAL implementation should + * return an error. + * * @param[in] obj The SPI peripheral to use for sending * @param[in] tx_buffer Pointer to the byte-array of data to write to the device * @param[in] tx_length Number of bytes to write, may be zero @@ -432,7 +436,7 @@ const PinMap *spi_slave_cs_pinmap(void); * @note On MCUs with a data cache, the return value is used to determine if a cache invalidation needs to be done * after the transfer is complete. If this function returns true, the driver layer will cache invalidate the Rx buffer under * the assumption that the data needs to be re-read from main memory. Be careful, because if the read was not actually - * done by DMA, and the rx data is in the CPU cache, this invalidation will corrupt it. + * done by DMA, and the rx data is in the CPU cache and NOT main memory, this invalidation will corrupt it. * * @note The application layer will always acquire the SPI peripheral first before calling this, including setting the frequency and the bit width. So, * the \c bit_width argument will never be different from the SPI's currently set bit width, and can actually be ignored. diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/CMakeLists.txt b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/CMakeLists.txt index d4d69c1705f..b4805c5b5e1 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/CMakeLists.txt +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/CMakeLists.txt @@ -50,6 +50,9 @@ target_sources(mbed-apollo3 device/spi_api.c device/us_ticker.c device/itm_api.c + device/analogin_api.c + device/pwmout_api.c + device/mbed_overrides.c sdk/CMSIS/AmbiqMicro/Source/system_apollo3.c diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h index 30e91115272..de438a5649b 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS/PinNames.h @@ -128,6 +128,9 @@ typedef enum SERIAL1_TX = IO_24, SERIAL1_RX = IO_25, + // Not a real pin on the device, but can be passed to AnalogIn to read the internal temperature sensor + INT_TEMP_SENSOR = 0x10000, + // Not connected NC = NC_VAL } PinName; @@ -140,11 +143,6 @@ typedef enum #define QWIIC_SCL I2C_SCL #define QWIIC_SDA I2C_SDA -// SPI bus -#define SPI_SCLK IO_5 -#define SPI_MOSI IO_7 -#define SPI_MISO IO_6 - #if defined(MBED_CONF_TARGET_STDIO_UART_TX) #define STDIO_UART_TX MBED_CONF_TARGET_STDIO_UART_TX #else diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_ATP/PinNames.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_ATP/PinNames.h index 24e2686fb06..c20bdeb8f5b 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_ATP/PinNames.h +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_ATP/PinNames.h @@ -164,6 +164,9 @@ typedef enum SERIAL1_TX = D24, SERIAL1_RX = D25, + // Not a real pin on the device, but can be passed to AnalogIn to read the internal temperature sensor + INT_TEMP_SENSOR = 0x10000, + // Not connected NC = NC_VAL } PinName; diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_DK/PinNames.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_DK/PinNames.h index d8da27c3180..f12f31daefe 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_DK/PinNames.h +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_DK/PinNames.h @@ -134,6 +134,9 @@ typedef enum CONSOLE_TX = SERIAL_TX, CONSOLE_RX = SERIAL_RX, + // Not a real pin on the device, but can be passed to AnalogIn to read the internal temperature sensor + INT_TEMP_SENSOR = 0x10000, + // Not connected NC = NC_VAL } PinName; diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_MODULE/PinNames.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_MODULE/PinNames.h index 494bbbcf502..d8aa5301703 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_MODULE/PinNames.h +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_MODULE/PinNames.h @@ -97,6 +97,9 @@ typedef enum CONSOLE_TX = SERIAL_TX, CONSOLE_RX = SERIAL_RX, + // Not a real pin on the device, but can be passed to AnalogIn to read the internal temperature sensor + INT_TEMP_SENSOR = 0x10000, + // Not connected NC = NC_VAL } PinName; diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_NANO/PinNames.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_NANO/PinNames.h index b19f9a50604..18514381921 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_NANO/PinNames.h +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_NANO/PinNames.h @@ -130,6 +130,9 @@ typedef enum SERIAL1_TX = D9, SERIAL1_RX = D10, + // Not a real pin on the device, but can be passed to AnalogIn to read the internal temperature sensor + INT_TEMP_SENSOR = 0x10000, + // Not connected NC = NC_VAL } PinName; diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_THING_PLUS/PinNames.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_THING_PLUS/PinNames.h index 7aedda12847..40ca09b1295 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_THING_PLUS/PinNames.h +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/TARGET_SFE_ARTEMIS_THING_PLUS/PinNames.h @@ -137,6 +137,9 @@ typedef enum SERIAL1_TX = D1, SERIAL1_RX = D0, + // Not a real pin on the device, but can be passed to AnalogIn to read the internal temperature sensor + INT_TEMP_SENSOR = 0x10000, + // Not connected NC = NC_VAL } PinName; diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/PeripheralNames.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/PeripheralNames.h index 4c3a534e2d6..0a25b7c982a 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/PeripheralNames.h +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/PeripheralNames.h @@ -46,6 +46,9 @@ typedef enum { IOM_ANY } IOMName; +// Each IOM can be used as an SPI +#define DEVICE_SPI_COUNT 6 + typedef IOMName SPIName; typedef IOMName I2CName; diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/PeripheralPins.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/PeripheralPins.c index 1eb737ddfcb..89781cb10cc 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/PeripheralPins.c +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/PeripheralPins.c @@ -17,6 +17,9 @@ #include "PeripheralPins.h" #include "PeripheralPinConfigs.h" +#include "am_hal_adc.h" +#include "objects.h" + /************RTC***************/ const PinMap PinMap_RTC[] = { {NC, 0, 0}, @@ -24,6 +27,17 @@ const PinMap PinMap_RTC[] = { /************ADC***************/ const PinMap PinMap_ADC[] = { + {11, ADC0_2, AM_HAL_PIN_11_ADCSE2}, + {12, ADC0_9, AM_HAL_PIN_12_ADCD0NSE9}, + {13, ADC0_8, AM_HAL_PIN_13_ADCD0PSE8}, + {16, ADC0_0, AM_HAL_PIN_16_ADCSE0}, + {29, ADC0_1, AM_HAL_PIN_29_ADCSE1}, + {31, ADC0_3, AM_HAL_PIN_31_ADCSE3}, + {32, ADC0_4, AM_HAL_PIN_32_ADCSE4}, + {33, ADC0_5, AM_HAL_PIN_33_ADCSE5}, + {34, ADC0_6, AM_HAL_PIN_34_ADCSE6}, + {35, ADC0_7, AM_HAL_PIN_35_ADCSE7}, + {INT_TEMP_SENSOR, ADC0_TEMP, 0}, {NC, NC, 0} }; @@ -253,6 +267,48 @@ const PinMap PinMap_SPI_SSEL[] = { }; /************PWM***************/ -const PinMap PinMap_PWM[] = { +// Note: The Apollo3 has fairly flexible PWM pin mapping options. Each IO pin which has a PWM function +// can actually map to one of 6 different PWM module outputs. However, there are as many PWM module +// outputs as there are pins, so we don't need to use this just to give every pin its own PWM output. +// For now, we always use the first possible option (Output Selection 2 in Table 814). +const PinMap PinMap_PWM_OUT[] = { + {IO_12, CTIMER_A0_OUT1, AM_HAL_PIN_12_CTIM0}, + {IO_25, CTIMER_A0_OUT2, AM_HAL_PIN_25_CTIM1}, + {IO_13, CTIMER_B0_OUT1, AM_HAL_PIN_13_CTIM2}, + {IO_26, CTIMER_B0_OUT2, AM_HAL_PIN_26_CTIM3}, + {IO_18, CTIMER_A1_OUT1, AM_HAL_PIN_18_CTIM4}, + {IO_27, CTIMER_A1_OUT2, AM_HAL_PIN_27_CTIM5}, + {IO_19, CTIMER_B1_OUT1, AM_HAL_PIN_19_CTIM6}, + {IO_28, CTIMER_B1_OUT2, AM_HAL_PIN_28_CTIM7}, + {IO_5, CTIMER_A2_OUT1, AM_HAL_PIN_5_CTIM8}, + {IO_29, CTIMER_A2_OUT2, AM_HAL_PIN_29_CTIM9}, + {IO_6, CTIMER_B2_OUT1, AM_HAL_PIN_6_CTIM10}, + {IO_30, CTIMER_B2_OUT2, AM_HAL_PIN_30_CTIM11}, + {IO_22, CTIMER_A3_OUT1, AM_HAL_PIN_22_CTIM12}, + {IO_31, CTIMER_A3_OUT2, AM_HAL_PIN_31_CTIM13}, + {IO_23, CTIMER_B3_OUT1, AM_HAL_PIN_23_CTIM14}, + {IO_32, CTIMER_B3_OUT2, AM_HAL_PIN_32_CTIM15}, + {IO_42, CTIMER_A4_OUT1, AM_HAL_PIN_42_CTIM16}, + {IO_4, CTIMER_A4_OUT2, AM_HAL_PIN_4_CTIM17}, + {IO_43, CTIMER_B4_OUT1, AM_HAL_PIN_43_CTIM18}, + {IO_7, CTIMER_B4_OUT2, AM_HAL_PIN_7_CTIM19}, + {IO_44, CTIMER_A5_OUT1, AM_HAL_PIN_44_CTIM20}, + {IO_24, CTIMER_A5_OUT2, AM_HAL_PIN_24_CTIM21}, + {IO_45, CTIMER_B5_OUT2, AM_HAL_PIN_45_CTIM22}, + {IO_33, CTIMER_B5_OUT2, AM_HAL_PIN_33_CTIM23}, + {IO_46, CTIMER_A6_OUT1, AM_HAL_PIN_46_CTIM24}, + {IO_47, CTIMER_B6_OUT1, AM_HAL_PIN_47_CTIM26}, + {IO_35, CTIMER_B6_OUT2, AM_HAL_PIN_35_CTIM27}, + + // Different from normal mapping since output selection 2 doesn't give a unique timer on this pin + {IO_39, CTIMER_A6_OUT2, AM_HAL_PIN_39_CTIM25}, + + // For these last four, we have to duplicate other timers, as CTIMER_x7 is + // used for the us ticker. + {IO_48, CTIMER_A3_OUT1, AM_HAL_PIN_48_CTIM28}, + {IO_37, CTIMER_A3_OUT2, AM_HAL_PIN_37_CTIM29}, + {IO_49, CTIMER_B3_OUT1, AM_HAL_PIN_49_CTIM30}, + {IO_11, CTIMER_B3_OUT2, AM_HAL_PIN_11_CTIM31}, + {NC, NC, 0} }; diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/analogin_api.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/analogin_api.c new file mode 100644 index 00000000000..df123d7d4f2 --- /dev/null +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/analogin_api.c @@ -0,0 +1,167 @@ +/* mbed Microcontroller Library + * Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "mbed_assert.h" +#include "analogin_api.h" +#include "pinmap.h" +#include "PeripheralPins.h" + +#include "am_hal_adc.h" + +void* am_adc_handle = NULL; + +// ADC constants +#define ADC_RESOLUTION_SEL AM_HAL_ADC_SLOT_14BIT +#define ADC_RESOLUTION_BITS 14 +#define ADC_CONVERSION_FACTOR (1.0f / (1 << ADC_RESOLUTION_BITS)) + +#define ADC_REFERENCE_SEL AM_HAL_ADC_REFSEL_INT_2P0 + +static uint32_t powerControlADC(bool on){ + uint32_t status = AM_HAL_STATUS_SUCCESS; + + if(on){ + status = am_hal_adc_initialize(0, &am_adc_handle); + if(status != AM_HAL_STATUS_SUCCESS){ return status; } + + status = am_hal_adc_power_control(am_adc_handle, AM_HAL_SYSCTRL_WAKE, false); + if(status != AM_HAL_STATUS_SUCCESS){ return status; } + }else{ + status = am_hal_adc_disable(am_adc_handle); + if(status != AM_HAL_STATUS_SUCCESS){ return status; } + + status = am_hal_pwrctrl_periph_disable(AM_HAL_PWRCTRL_PERIPH_ADC); + if(status != AM_HAL_STATUS_SUCCESS){ return status; } + + status = am_hal_adc_deinitialize(am_adc_handle); + if(status != AM_HAL_STATUS_SUCCESS){ return status; } + } + + return status; +} + +static uint32_t initializeADC( void ){ + am_hal_adc_config_t ADCConfig; + + // Power on the ADC. + powerControlADC(true); + + // Set up the ADC configuration parameters. These settings are reasonable + // for accurate measurements at a low sample rate. + ADCConfig.eClock = AM_HAL_ADC_CLKSEL_HFRC; + ADCConfig.ePolarity = AM_HAL_ADC_TRIGPOL_RISING; + ADCConfig.eTrigger = AM_HAL_ADC_TRIGSEL_SOFTWARE; + ADCConfig.eReference = ADC_REFERENCE_SEL; + ADCConfig.eClockMode = AM_HAL_ADC_CLKMODE_LOW_LATENCY; + ADCConfig.ePowerMode = AM_HAL_ADC_LPMODE0; + ADCConfig.eRepeat = AM_HAL_ADC_SINGLE_SCAN; + + return am_hal_adc_configure(am_adc_handle, &ADCConfig); +} + + +void analogin_init(analogin_t *obj, PinName pin) +{ + // Find ADC slot and pin from pinmap + const am_hal_adc_slot_chan_e adcSlot = pinmap_peripheral(pin, PinMap_ADC); + const uint32_t pinFunction = pinmap_function(pin, PinMap_ADC); + + // Configure pin as an analog pin + am_hal_gpio_pincfg_t pincfg = g_AM_HAL_GPIO_INPUT; + pincfg.uFuncSel = pinFunction; + am_hal_gpio_pinconfig(pin, pincfg); + + /* Initialize the ADC the first time it is being used, + * but don't reinitialize it again afterwards. + */ + static bool is_adc_initialized = false; + if (!is_adc_initialized) + { + initializeADC(); + is_adc_initialized = true; + } + + obj->slot = adcSlot; +} + +// Reconfigure ADC slot 0 to target the given channel +static void ap3_config_channel(am_hal_adc_slot_chan_e channel){ + am_hal_adc_slot_config_t ADCSlotConfig; + + // Set up an ADC slot + ADCSlotConfig.eMeasToAvg = AM_HAL_ADC_SLOT_AVG_1; + ADCSlotConfig.ePrecisionMode = ADC_RESOLUTION_SEL; + ADCSlotConfig.eChannel = channel; + ADCSlotConfig.bWindowCompare = false; + ADCSlotConfig.bEnabled = true; + + MBED_ASSERT(am_hal_adc_disable(am_adc_handle) == AM_HAL_STATUS_SUCCESS); + + MBED_ASSERT(am_hal_adc_configure_slot(am_adc_handle, 0, &ADCSlotConfig) == AM_HAL_STATUS_SUCCESS); + + MBED_ASSERT(am_hal_adc_enable(am_adc_handle) == AM_HAL_STATUS_SUCCESS); +} + +// Read an analog in channel as a 14-bit number +static uint16_t readAnalogIn(analogin_t *obj) +{ + // Target this channel + ap3_config_channel(obj->slot); + + // Clear any set interrupt flags + uint32_t intStatus; + am_hal_adc_interrupt_status(am_adc_handle, &intStatus, false); + MBED_ASSERT(AM_HAL_STATUS_SUCCESS == am_hal_adc_interrupt_clear(am_adc_handle, intStatus)); + + // Issue SW trigger + am_hal_adc_sw_trigger(am_adc_handle); + + do { // Wait for conversion complete interrupt + MBED_ASSERT(AM_HAL_STATUS_SUCCESS == am_hal_adc_interrupt_status(am_adc_handle, &intStatus, false)); + } while(!(intStatus & AM_HAL_ADC_INT_CNVCMP)); + MBED_ASSERT(AM_HAL_STATUS_SUCCESS == am_hal_adc_interrupt_clear(am_adc_handle, intStatus)); + + uint32_t numSamplesToRead = 1; + am_hal_adc_sample_t sample; + MBED_ASSERT(AM_HAL_STATUS_SUCCESS == am_hal_adc_samples_read(am_adc_handle, false, NULL, &numSamplesToRead, &sample)); + + return sample.ui32Sample; +} + +uint16_t analogin_read_u16(analogin_t *obj) +{ + uint16_t reading = readAnalogIn(obj); + + /* Return a 16-Bit ADC value. */ + return reading << (16 - ADC_RESOLUTION_BITS); +} + +float analogin_read(analogin_t *obj) +{ + /* Read the raw 14-Bit value from the ADC. */ + uint16_t analog_in_raw = readAnalogIn(obj); + + /* Convert it to a voltage value. */ + return (analog_in_raw * ADC_CONVERSION_FACTOR); +} + + +const PinMap *analogin_pinmap() +{ + return PinMap_ADC; +} diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/mbed_overrides.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/mbed_overrides.c new file mode 100644 index 00000000000..dabad60dea0 --- /dev/null +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/mbed_overrides.c @@ -0,0 +1,33 @@ +/* mbed Microcontroller Library + * Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +// Needed for am_hal_clkgen.h +#include +#include + +#include + +void mbed_sdk_init(void) +{ + // Turn on frequency adjustment. This improves HFRC clock accuracy by a factor + // of 10 or more. + am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_HFADJ_ENABLE, NULL); +} \ No newline at end of file diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/objects.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/objects.h index f94c6422588..916548ff26e 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/objects.h +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/objects.h @@ -21,19 +21,13 @@ #include "am_bsp.h" #include "am_util.h" -#ifdef __cplusplus -extern "C" { -#endif - #include "objects_flash.h" #include "objects_gpio.h" #include "objects_uart.h" #include "objects_iom.h" #include "objects_spi.h" #include "objects_i2c.h" - -#ifdef __cplusplus -} -#endif +#include "objects_adc.h" +#include "objects_pwm.h" #endif diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/objects_adc.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/objects_adc.h new file mode 100644 index 00000000000..fd29e9af016 --- /dev/null +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/objects_adc.h @@ -0,0 +1,57 @@ +/* mbed Microcontroller Library + * Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBJECTS_ADC_H +#define OBJECTS_ADC_H + +#include "am_hal_adc.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// ADC input names +typedef enum { + ADC0_0 = AM_HAL_ADC_SLOT_CHSEL_SE0, + ADC0_1 = AM_HAL_ADC_SLOT_CHSEL_SE1, + ADC0_2 = AM_HAL_ADC_SLOT_CHSEL_SE2, + ADC0_3 = AM_HAL_ADC_SLOT_CHSEL_SE3, + ADC0_4 = AM_HAL_ADC_SLOT_CHSEL_SE4, + ADC0_5 = AM_HAL_ADC_SLOT_CHSEL_SE5, + ADC0_6 = AM_HAL_ADC_SLOT_CHSEL_SE6, + ADC0_7 = AM_HAL_ADC_SLOT_CHSEL_SE7, + ADC0_8 = AM_HAL_ADC_SLOT_CHSEL_SE8, + ADC0_9 = AM_HAL_ADC_SLOT_CHSEL_SE9, + ADC0_TEMP = AM_HAL_ADC_SLOT_CHSEL_TEMP +} ADCName; + +struct analogin_s +{ + // Slot that this ADC input connects to on the ADC + am_hal_adc_slot_chan_e slot; +}; + +// Opaque handle to the ADC peripheral. This is needed to +// use certain AM HAL calls from user code. This will be initialized +// the first time that any AnalogIn is initialized. +extern void* am_adc_handle; + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/objects_pwm.h b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/objects_pwm.h new file mode 100644 index 00000000000..7a99aa1de91 --- /dev/null +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/objects_pwm.h @@ -0,0 +1,120 @@ +/* mbed Microcontroller Library + * Copyright (c) 2025 Jamie Smith + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef OBJECTS_PWM_H +#define OBJECTS_PWM_H + +#include "am_hal_ctimer.h" + +#ifdef __cplusplus +extern "C" { +#endif + +// This MCU has 8 CTIMER modules, each of which contains two segments. The two segments are functionally independent +// except that the B segment can optionally be combined with the A segment for a 32-bit counter (which we don't use). +// Each segment has two independent compare outputs, meaning that we have a total of 32 possible PWM outputs. + +// PWM name is composed of the CTIMER number, whether it's an A or B segment, and whether this is the first or second +// output from it. +#define APOLLO3_PWM_NAME(ctimerNum, aOrB, outputNum) ((ctimerNum << 2) | (aOrB << 1) | outputNum) + +typedef enum { + CTIMER_A0_OUT1 = APOLLO3_PWM_NAME(0, 0, 0), + CTIMER_A0_OUT2 = APOLLO3_PWM_NAME(0, 0, 1), + + CTIMER_A1_OUT1 = APOLLO3_PWM_NAME(1, 0, 0), + CTIMER_A1_OUT2 = APOLLO3_PWM_NAME(1, 0, 1), + + CTIMER_A2_OUT1 = APOLLO3_PWM_NAME(2, 0, 0), + CTIMER_A2_OUT2 = APOLLO3_PWM_NAME(2, 0, 1), + + CTIMER_A3_OUT1 = APOLLO3_PWM_NAME(3, 0, 0), + CTIMER_A3_OUT2 = APOLLO3_PWM_NAME(3, 0, 1), + + CTIMER_A4_OUT1 = APOLLO3_PWM_NAME(4, 0, 0), + CTIMER_A4_OUT2 = APOLLO3_PWM_NAME(4, 0, 1), + + CTIMER_A5_OUT1 = APOLLO3_PWM_NAME(5, 0, 0), + CTIMER_A5_OUT2 = APOLLO3_PWM_NAME(5, 0, 1), + + CTIMER_A6_OUT1 = APOLLO3_PWM_NAME(6, 0, 0), + CTIMER_A6_OUT2 = APOLLO3_PWM_NAME(6, 0, 1), + + CTIMER_A7_OUT1 = APOLLO3_PWM_NAME(7, 0, 0), + CTIMER_A7_OUT2 = APOLLO3_PWM_NAME(7, 0, 1), + + CTIMER_B0_OUT1 = APOLLO3_PWM_NAME(0, 1, 0), + CTIMER_B0_OUT2 = APOLLO3_PWM_NAME(0, 1, 1), + + CTIMER_B1_OUT1 = APOLLO3_PWM_NAME(1, 1, 0), + CTIMER_B1_OUT2 = APOLLO3_PWM_NAME(1, 1, 1), + + CTIMER_B2_OUT1 = APOLLO3_PWM_NAME(2, 1, 0), + CTIMER_B2_OUT2 = APOLLO3_PWM_NAME(2, 1, 1), + + CTIMER_B3_OUT1 = APOLLO3_PWM_NAME(3, 1, 0), + CTIMER_B3_OUT2 = APOLLO3_PWM_NAME(3, 1, 1), + + CTIMER_B4_OUT1 = APOLLO3_PWM_NAME(4, 1, 0), + CTIMER_B4_OUT2 = APOLLO3_PWM_NAME(4, 1, 1), + + CTIMER_B5_OUT1 = APOLLO3_PWM_NAME(5, 1, 0), + CTIMER_B5_OUT2 = APOLLO3_PWM_NAME(5, 1, 1), + + CTIMER_B6_OUT1 = APOLLO3_PWM_NAME(6, 1, 0), + CTIMER_B6_OUT2 = APOLLO3_PWM_NAME(6, 1, 1), + + CTIMER_B7_OUT1 = APOLLO3_PWM_NAME(7, 1, 0), + CTIMER_B7_OUT2 = APOLLO3_PWM_NAME(7, 1, 1), +} PWMName; + +// Get the CTIMER number of a PWM +#define APOLLO3_PWMNAME_GET_CTIMER(pwm_name) (pwm_name >> 2) + +// Convert from PWM name to AM_HAL_CTIMER_TIMERA/AM_HAL_CTIMER_TIMERB macro +#define APOLLO3_PWMNAME_GET_SEGMENT(pwm_name) (pwm_name & 0b10 ? AM_HAL_CTIMER_TIMERB : AM_HAL_CTIMER_TIMERA) + +// Convert from PWM name to AM_HAL_CTIMER_OUTPUT_NORMAL/AM_HAL_CTIMER_OUTPUT_SECONDARY enum value +#define APOLLO3_PWMNAME_GET_OUTPUT(pwm_name) (pwm_name & 0b1 ? AM_HAL_CTIMER_OUTPUT_SECONDARY : AM_HAL_CTIMER_OUTPUT_NORMAL) + +struct pwmout_s +{ + // Pin that the channel is on + PinName pin; + + // PWM name that this channel is using + PWMName pwm_name; + + // True iff the pin is connected to the PWM timer + bool pin_is_connected_to_pwm; + + // Clock period configured on this PWM, in floating point seconds + float clock_period; + + // Number of counts that the PWM output will make before a new PWM cycle starts + uint32_t top_count; + + // Number of counts that the PWM output will stay on for. + // Zero = full off, top_count = full on + uint32_t on_counts; +}; + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/pwmout_api.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/pwmout_api.c new file mode 100644 index 00000000000..446ad106b8e --- /dev/null +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/pwmout_api.c @@ -0,0 +1,260 @@ +/* mbed Microcontroller Library + * Copyright (c) 2024, Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#if DEVICE_PWMOUT + +#include "hal/pwmout_api.h" +#include "PeripheralPins.h" +#include "pinmap.h" +#include "objects.h" +#include "mbed_assert.h" +#include + +#include +#include + +// Change to 1 to enable debug prints of what's being calculated. +// Must comment out the critical section calls in PwmOut to use. +#define APOLLO3_PWMOUT_DEBUG 0 + +#if APOLLO3_PWMOUT_DEBUG +#include +#include +#endif + +struct pwm_clock_freq { + uint32_t clock_setting; + float frequency; +}; + +// Table of options for PWM clock source vs clock frequency, in decreasing order of clock frequency +// Note that the Apollo3 uses a fixed external oscillator frequency, so this is possible to define statically. +// There are three oscillators available, each of which can be used for PWM: +// - HFRC - internal high freq RC oscillator, 48MHz +-3.5% uncalibrated, but better with auto-calibration. +// - XT - external crystal, 32.768kHz, likely 50ppm or better tolerance +// - LFRC - internal low freq RC oscillator, 1.024kHz +-32% (no that's not a typo!) +// This means we have quite a wide range of base clock frequencies available, though period accuracy will be pretty +// poor if the LFRC gets selected. +#define NUM_CLOCK_SOURCE_OPTIONS 16 +#define HFRC_FREQ 48000000 +#define XT_FREQ 32768 +#define LFRC_FREQ 1024 +static const struct pwm_clock_freq pwm_clock_sources[NUM_CLOCK_SOURCE_OPTIONS] = { + {AM_HAL_CTIMER_HFRC_12MHZ, HFRC_FREQ/4.0f}, + {AM_HAL_CTIMER_HFRC_3MHZ, HFRC_FREQ/16.0f}, + {AM_HAL_CTIMER_HFRC_187_5KHZ, HFRC_FREQ/256.0f}, + {AM_HAL_CTIMER_HFRC_47KHZ, HFRC_FREQ/1024.0f}, + {AM_HAL_CTIMER_XT_32_768KHZ, XT_FREQ}, + {AM_HAL_CTIMER_XT_16_384KHZ, XT_FREQ/2.0f}, + {AM_HAL_CTIMER_HFRC_12KHZ, HFRC_FREQ/4096.0f}, + {AM_HAL_CTIMER_XT_DIV4,XT_FREQ/4.0f}, + {AM_HAL_CTIMER_XT_DIV8,XT_FREQ/8.0f}, + {AM_HAL_CTIMER_XT_2_048KHZ, XT_FREQ/16.0f}, + {AM_HAL_CTIMER_XT_DIV32,XT_FREQ/32.0f}, + + // Note: NOT adding this one because the accuracy is bad + // {AM_HAL_CTIMER_LFRC_512HZ, LFRC_FREQ/2.0f}, + + {AM_HAL_CTIMER_XT_256HZ, XT_FREQ/128.0f}, + {AM_HAL_CTIMER_LFRC_32HZ, LFRC_FREQ/32.0f}, + {AM_HAL_CTIMER_LFRC_1HZ, LFRC_FREQ/1024.0f}, + + // Note: there may also be a 1/16Hz clock source option, but the SDK and datasheet seem + // to disagree about it. +}; + +/// Largest top count value supported by hardware. Using this value will provide the highest duty cycle resolution. +/// The hardware performs (CMPR register value + 1) counts and it's a 16-bit register, so the actual max top count is 2^16. +const uint32_t MAX_TOP_COUNT = 65536; + +void pwmout_init(pwmout_t *obj, PinName pin) +{ + MBED_ASSERT(obj != NULL); + + // Find PWM module from pinmap + const PWMName pwmName = pinmap_peripheral(pin, PinMap_PWM_OUT); + + /* Populate PWM object with values. */ + memset(obj, 0, sizeof(pwmout_t)); + obj->pwm_name = pwmName; + obj->pin = pin; +} + +void pwmout_free(pwmout_t *obj) +{ + MBED_ASSERT(obj != NULL); + am_hal_ctimer_stop(APOLLO3_PWMNAME_GET_CTIMER(obj->pwm_name), + APOLLO3_PWMNAME_GET_SEGMENT(obj->pwm_name)); +} + +void pwmout_write(pwmout_t *obj, float percent) +{ + MBED_ASSERT(obj != NULL); + if (percent < 0 || percent > 1) { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_PWM, MBED_ERROR_CODE_INVALID_ARGUMENT), "Invalid PWM duty cycle!"); + } + + // Calculate how many counts out of top_count we should be on + obj->on_counts = lroundf(percent * obj->top_count); + +#if APOLLO3_PWMOUT_DEBUG + printf("obj->on_counts: %" PRIu32 "\n", obj->on_counts); +#endif + + // If we want 0% or 100% duty cycle, we need to do that by connecting the pin to forceed 0 or forced 1 + if (obj->on_counts == 0 || obj->on_counts == obj->top_count) { + am_hal_ctimer_stop(APOLLO3_PWMNAME_GET_CTIMER(obj->pwm_name), + APOLLO3_PWMNAME_GET_SEGMENT(obj->pwm_name)); + am_hal_ctimer_output_config(APOLLO3_PWMNAME_GET_CTIMER(obj->pwm_name), + APOLLO3_PWMNAME_GET_SEGMENT(obj->pwm_name), + obj->pin, + obj->on_counts == 0 ? AM_HAL_CTIMER_OUTPUT_FORCE0 : AM_HAL_CTIMER_OUTPUT_FORCE1, + AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA); + obj->pin_is_connected_to_pwm = false; + } + else { + + // If the pin is not connected to the PWM timer, set that up + if (!obj->pin_is_connected_to_pwm) { + am_hal_ctimer_output_config(APOLLO3_PWMNAME_GET_CTIMER(obj->pwm_name), + APOLLO3_PWMNAME_GET_SEGMENT(obj->pwm_name), + obj->pin, + APOLLO3_PWMNAME_GET_OUTPUT(obj->pwm_name), + AM_HAL_GPIO_PIN_DRIVESTRENGTH_12MA); + obj->pin_is_connected_to_pwm = true; + } + + // Set new period value. Note that: + // - We have to set the top count and the on count at the same time + // - The HW adds 1 to the programmed values, so we have to subtract 1 when passing them in + if(APOLLO3_PWMNAME_GET_OUTPUT(obj->pwm_name) == AM_HAL_CTIMER_OUTPUT_NORMAL) { + am_hal_ctimer_period_set(APOLLO3_PWMNAME_GET_CTIMER(obj->pwm_name), + APOLLO3_PWMNAME_GET_SEGMENT(obj->pwm_name), + obj->top_count - 1, + obj->on_counts - 1); + } + else { + am_hal_ctimer_aux_period_set(APOLLO3_PWMNAME_GET_CTIMER(obj->pwm_name), + APOLLO3_PWMNAME_GET_SEGMENT(obj->pwm_name), + obj->top_count - 1, + obj->on_counts - 1); + } + + // Start timer if not running + am_hal_ctimer_start(APOLLO3_PWMNAME_GET_CTIMER(obj->pwm_name), + APOLLO3_PWMNAME_GET_SEGMENT(obj->pwm_name)); + } +} + +float pwmout_read(pwmout_t *obj) +{ + return ((float)obj->on_counts) / obj->top_count; +} + +void pwmout_period(pwmout_t *obj, const float desired_period) +{ + MBED_ASSERT(obj != NULL); + const float old_duty_cycle = pwmout_read(obj); + + // To find the period, we perform the following steps: + // - Determine the fastest clock frequency that we can use while still hitting the needed period + // - Calculate the correct top_count value that will produce as close to the desired period as possible + // - Write the new top_count value into the hardware + + size_t clk_source_idx; + bool found_clk_source = false; + for(clk_source_idx = 0; clk_source_idx < NUM_CLOCK_SOURCE_OPTIONS; ++clk_source_idx) { + const float divider_max_period = MAX_TOP_COUNT / pwm_clock_sources[clk_source_idx].frequency; + if(divider_max_period >= desired_period) { + found_clk_source = true; + break; + } + } + if(!found_clk_source) { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_PWM, MBED_ERROR_CODE_INVALID_ARGUMENT), "Clock frequency too slow!"); + } + + // Now that we have found the best clock source, calculate top_count to hit the desired period + obj->clock_period = 1.0f / pwm_clock_sources[clk_source_idx].frequency; + obj->top_count = lroundf(desired_period / obj->clock_period); + + // The hardware cannot support a top_count of less than 2. If that happened than it means the + // frequency is too fast. + if(obj->top_count < 2) { + MBED_ERROR(MBED_MAKE_ERROR(MBED_MODULE_DRIVER_PWM, MBED_ERROR_CODE_INVALID_ARGUMENT), "Clock frequency too fast!"); + } + +#if APOLLO3_PWMOUT_DEBUG + printf("clk_source_idx = %zu, obj->clock_period = %f ms, obj->top_count = %" PRIu32 "\n", + clk_source_idx, + obj->clock_period*1e3f, + obj->top_count); +#endif + + // Set new clock source. This stops the timer. + am_hal_ctimer_config_single(APOLLO3_PWMNAME_GET_CTIMER(obj->pwm_name), + APOLLO3_PWMNAME_GET_SEGMENT(obj->pwm_name), + AM_HAL_CTIMER_FN_PWM_REPEAT | pwm_clock_sources[clk_source_idx].clock_setting); + + // Set the old duty cycle, which also writes the period and starts the timer + pwmout_write(obj, old_duty_cycle); +} + +void pwmout_period_ms(pwmout_t *obj, int period) +{ + /* Set new period. */ + pwmout_period(obj, period / 1000.0f); +} + +void pwmout_period_us(pwmout_t *obj, int period) +{ + /* Set new period. */ + pwmout_period(obj, period / 1000000.0f); +} + +int pwmout_read_period_us(pwmout_t *obj) +{ + MBED_ASSERT(obj != NULL); + return lroundf(1e6f * obj->top_count * obj->clock_period); +} + +void pwmout_pulsewidth(pwmout_t *obj, float pulse) +{ + pwmout_write(obj, pulse / (obj->top_count * obj->clock_period)); +} + +void pwmout_pulsewidth_ms(pwmout_t *obj, int pulse) +{ + pwmout_write(obj, (pulse * .001f) / (obj->top_count * obj->clock_period)); +} + +void pwmout_pulsewidth_us(pwmout_t *obj, int pulse) +{ + pwmout_write(obj, (pulse * .000001f) / (obj->top_count * obj->clock_period)); +} + +int pwmout_read_pulsewidth_us(pwmout_t *obj) { + return lroundf(obj->on_counts * obj->clock_period * 1e6f); +} + +const PinMap *pwmout_pinmap() +{ + return PinMap_PWM_OUT; +} + +#endif // DEVICE_PWMOUT diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/spi_api.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/spi_api.c index ebfb737a555..84bc6181497 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/spi_api.c +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/spi_api.c @@ -70,8 +70,8 @@ void spi_get_capabilities(PinName ssel, bool slave, spi_capabilities_t *cap) cap->word_length = 0x00000080; cap->slave_delay_between_symbols_ns = 0; cap->clk_modes = 0x0F; - cap->support_slave_mode = (iom_ssel == IOM_ANY) ? true : false; - cap->hw_cs_handle = false; + cap->support_slave_mode = false; + cap->hw_cs_handle = iom_ssel == IOM_ANY; cap->async_mode = false; cap->tx_rx_buffers_equal_length = false; } diff --git a/targets/targets.json5 b/targets/targets.json5 index 4b4c7102e41..7101154834c 100644 --- a/targets/targets.json5 +++ b/targets/targets.json5 @@ -9693,7 +9693,9 @@ mode is recommended for target MCUs with small amounts of flash and RAM.", "SPI", "I2C", "SLEEP", - "ITM" + "ITM", + "ANALOGIN", + "PWMOUT" ], "macros": [ "CORDIO_ZERO_COPY_HCI", @@ -9710,14 +9712,21 @@ mode is recommended for target MCUs with small amounts of flash and RAM.", "std", "small" ] - } + }, + + "overrides": { + // Currently the analog in HAL driver sets the voltage reference to the internal 2V reference + // (though the hardware also has a 1.5V reference and an external ref input) + "default-adc-vref": 2.0 + }, + + "is_mcu_family_target": true }, "AMA3B1KK": { "public": false, "inherits": ["FAMILY_Apollo3"], "macros_add": ["AM_PACKAGE_BGA", "MBED_TICKLESS"], "device_name": "AMA3B1KK-KBR", - "is_mcu_family_target": true, "memory_bank_config": { // Leave room for the SparkFun SVL bootloader in flash "IROM1": { diff --git a/targets/upload_method_cfg/common/SFE_ARTEMIS_DK.cmake b/targets/upload_method_cfg/SFE_ARTEMIS_DK.cmake similarity index 67% rename from targets/upload_method_cfg/common/SFE_ARTEMIS_DK.cmake rename to targets/upload_method_cfg/SFE_ARTEMIS_DK.cmake index 88f964402c7..00d944661e6 100644 --- a/targets/upload_method_cfg/common/SFE_ARTEMIS_DK.cmake +++ b/targets/upload_method_cfg/SFE_ARTEMIS_DK.cmake @@ -3,10 +3,7 @@ # include mbed_toolchain_setup and where you add mbed-os as a subdirectory. # Notes: -# 1. Support for this device exists in PyOCD main branch but has not been released yet (as of Jun 2025). -# This version will be used automatically by Mbed if the python venv is enabled. If not, you need to install it via: -# pip install git+https://github.com/pyocd/pyOCD.git -# 2. Unlike all other SparkFun Artemis boards, this board has a CMSIS-DAP interface MCU on it, so it +# 1. Unlike all other SparkFun Artemis boards, this board has a CMSIS-DAP interface MCU on it, so it # should be debuggable & flashable out of the box via PyOCD. set(UPLOAD_METHOD_DEFAULT MBED) @@ -17,6 +14,13 @@ set(PYOCD_UPLOAD_ENABLED TRUE) set(PYOCD_TARGET_NAME ama3b1kk_kbr) set(PYOCD_CLOCK_SPEED 4000k) +# Config options for JLINK +# ------------------------------------------------------------- +set(JLINK_UPLOAD_ENABLED TRUE) +set(JLINK_CPU_NAME AMA3B1KK-KBR) +set(JLINK_CLOCK_SPEED 4000) +set(JLINK_UPLOAD_INTERFACE SWD) + # Config options for MBED # ------------------------------------------------------------- set(MBED_UPLOAD_ENABLED TRUE) \ No newline at end of file diff --git a/targets/upload_method_cfg/common/sparkfun_artemis.cmake b/targets/upload_method_cfg/common/sparkfun_artemis.cmake index 4f81da3c820..3ee970b5805 100644 --- a/targets/upload_method_cfg/common/sparkfun_artemis.cmake +++ b/targets/upload_method_cfg/common/sparkfun_artemis.cmake @@ -5,9 +5,6 @@ # Notes: # 1. This board does not have an onboard debugger. You must use an external debugger, e.g. a PicoProbe # or J-Link, if you wish to debug code. -# 2. Support for this device exists in PyOCD main branch but has not been released yet (as of Jun 2025). -# This version will be used automatically by Mbed if the python venv is enabled. If not, you need to install it via: -# pip install git+https://github.com/pyocd/pyOCD.git set(UPLOAD_METHOD_DEFAULT AMBIQ_SVL) diff --git a/tools/cmake/mbed_python_interpreter.cmake b/tools/cmake/mbed_python_interpreter.cmake index 39ff80a110d..1d563c3ac28 100644 --- a/tools/cmake/mbed_python_interpreter.cmake +++ b/tools/cmake/mbed_python_interpreter.cmake @@ -38,7 +38,8 @@ if(MBED_CREATE_PYTHON_VENV) message(STATUS "Python venv deleted or unusable. Recreating using system Python...") # Launch a new search for Python3 - unset(Python3_EXECUTABLE) + unset(Python3_EXECUTABLE CACHE) + unset(Python_EXECUTABLE CACHE) unset(_Python3_EXECUTABLE CACHE) unset(_Python3_INTERPRETER_PROPERTIES CACHE) unset(_Python3_INTERPRETER_SIGNATURE CACHE) diff --git a/tools/cmake/upload_methods/UploadMethodPYOCD.cmake b/tools/cmake/upload_methods/UploadMethodPYOCD.cmake index 04949ba2674..b6ca4ec8945 100644 --- a/tools/cmake/upload_methods/UploadMethodPYOCD.cmake +++ b/tools/cmake/upload_methods/UploadMethodPYOCD.cmake @@ -11,9 +11,8 @@ set(UPLOAD_SUPPORTS_DEBUG TRUE) ### Find PyOCD package -# Use the Git version so that we get Ambiq Apollo3 support (as that was not included in the latest release -# before PyOCD development stopped, as of Jun 2025) -mbed_check_or_install_python_package(HAVE_PYTHON_PYOCD pyocd git+https://github.com/pyocd/pyOCD.git) +# Use >=0.37 so that we get Ambiq Apollo3 support +mbed_check_or_install_python_package(HAVE_PYTHON_PYOCD pyocd pyocd>=0.37) set(UPLOAD_PYOCD_FOUND ${HAVE_PYTHON_PYOCD})