Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Evan/uart #214

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ modules += neuralspot/ns-ipc
modules += neuralspot/ns-audio
modules += neuralspot/ns-utils
modules += neuralspot/ns-features
modules += neuralspot/ns-uart

# ifeq ($(ARCH),apollo4)
modules += neuralspot/ns-i2c
Expand Down Expand Up @@ -77,6 +78,7 @@ else
ifeq ($(EXAMPLE),all)
modules += examples/basic_tf_stub
modules += examples/har
modules += examples/uart

ifeq ($(BLE_SUPPORTED),1)
modules += examples/nnse
Expand Down
13 changes: 13 additions & 0 deletions examples/uart/module.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
local_app_name := uart
local_src := $(wildcard $(subdirectory)/src/*.c)
local_src += $(wildcard $(subdirectory)/src/*.cc)
local_src += $(wildcard $(subdirectory)/src/*.cpp)
local_src += $(wildcard $(subdirectory)/src/*.s)
local_bin := $(BINDIR)/$(subdirectory)

bindirs += $(local_bin)
# sources += $(local_src)
examples += $(local_bin)/$(local_app_name).axf
examples += $(local_bin)/$(local_app_name).bin
# mains += $(local_bin)/src/$(local_app_name).o
$(eval $(call make-axf, $(local_bin)/$(local_app_name), $(local_src)))
78 changes: 78 additions & 0 deletions examples/uart/src/uart.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@


#include "ns_core.h"
#include "ns_ambiqsuite_harness.h"
#include "ns_peripherals_power.h"
#include "ns_timer.h"
#include "am_hal_mcuctrl.h"
#include "ns_uart.h"
#include <stdio.h>
#include <string.h>
#include "ns_peripherals_button.h"

#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
#define RX_BUFFER_SIZE 256
#define TX_BUFFER_SIZE 256
static uint8_t g_pui8TxBuffer[TX_BUFFER_SIZE];
static uint8_t g_pui8RxBuffer[RX_BUFFER_SIZE];
#endif

// UART0 interrupt handler.
am_hal_uart_config_t g_sUartConfig =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this should be 'hidden' behind the ns_uart API (generally, ns examples should have minimal ambiqsuite code).

{
// Standard UART settings: 115200-8-N-1
.ui32BaudRate = 115200,
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
.ui32DataBits = AM_HAL_UART_DATA_BITS_8,
// Set TX and RX FIFOs to interrupt at half-full.
.ui32Parity = AM_HAL_UART_PARITY_NONE,
.ui32StopBits = AM_HAL_UART_ONE_STOP_BIT,
.ui32FlowControl = AM_HAL_UART_FLOW_CTRL_NONE,
.ui32FifoLevels = (AM_HAL_UART_TX_FIFO_1_2 |
AM_HAL_UART_RX_FIFO_1_2),
// Buffers
.pui8TxBuffer = g_pui8TxBuffer,
.ui32TxBufferSize = (uint32_t) sizeof(g_pui8TxBuffer),
.pui8RxBuffer = g_pui8RxBuffer,
.ui32RxBufferSize = (uint32_t) sizeof(g_pui8RxBuffer),
#endif
#if defined(AM_PART_APOLLO4) || defined(AM_PART_APOLLO4P) || defined(AM_PART_APOLLO4L)
.eDataBits = AM_HAL_UART_DATA_BITS_8,
.eParity = AM_HAL_UART_PARITY_NONE,
.eStopBits = AM_HAL_UART_ONE_STOP_BIT,
.eFlowControl = AM_HAL_UART_FLOW_CTRL_NONE,
.eTXFifoLevel = AM_HAL_UART_FIFO_LEVEL_16,
.eRXFifoLevel = AM_HAL_UART_FIFO_LEVEL_16,
#endif
};
ns_uart_config_t uart_config = {
.api=&ns_uart_V0_0_1,
.uart_config = &g_sUartConfig,
};
int main(void) {
ns_core_config_t ns_core_cfg = {.api = &ns_core_V1_0_0};
NS_TRY(ns_core_init(&ns_core_cfg), "Core init failed.\n");
uint32_t opusBegin, opusEnd;
#if defined(AM_PART_APOLLO3) || defined(AM_PART_APOLLO3P)
am_hal_clkgen_control(AM_HAL_CLKGEN_CONTROL_SYSCLK_MAX, 0); // nada
#endif
NS_TRY(ns_power_config(&ns_development_default), "Power Init Failed.\n");
// NS_TRY(ns_set_performance_mode(NS_MINIMUM_PERF), "Set CPU Perf mode failed.");
ns_itm_printf_enable(); // nada

ns_lp_printf("UART init\n");
NS_TRY(ns_uart_init(&uart_config), "UART init failed.\n");
ns_interrupt_master_enable();

ns_lp_printf("UART init done\n");
char buffer[] = "hello world";
char rxBuffer[12];
while(1) {
// Send data over UART
ns_uart_send_data(&uart_config, buffer, (uint32_t)sizeof(buffer) - 1);
// Receive data over UART
ns_uart_receive_data(&uart_config, rxBuffer, (uint32_t)sizeof(rxBuffer));
strcpy(buffer, (char *)rxBuffer);
ns_delay_us(500000);
}
}
14 changes: 14 additions & 0 deletions examples/uart/src/uart.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @file uart.h
* @author Evan Chen
* @brief
* @version 0.1
* @date 2024-12-04
*
* @copyright Copyright (c) 2024
*
*/

/// Assorted Configs and helpers
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
59 changes: 59 additions & 0 deletions examples/uart/src/uart_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import serial
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You need stress tests too - hit the uart as hard as you can in each direction (random transfer sizes, long blocks, lots an lots of blocks, lots of tiny blocks, mix tx and rx). The fact that send_data doesn't have error handling tells me you need to try harder to cause errors. I guarantee you erpc will, and it'll be easier to debug a test than rpc.

import time

# Configure the serial port
SERIAL_PORT = '/dev/tty.usbmodem0011600012981' # apollo4l serial port
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a way to find the port automatically by looking for a uuid - see https://github.com/AmbiqAI/ns-mirror/blob/4c18e561603651d922afdaa26dedb8fbddccd78d/tools/ns_utils.py#L195 for how I did it for autodeploy

# SERIAL_PORT = '/dev/tty.usbmodem0011600007091' # apollo4p serial port
# SERIAL_PORT = '/dev/tty.usbmodem0011600002531' # apollo3p serial port
# SERIAL_PORT = '/dev/tty.usbmodem0004831355981' # apollo3 serial port
# SERIAL_PORT = '/dev/tty.usbmodem0011600015811' # apollo4 blue lite serial port
# SERIAL_PORT = '/dev/tty.usbmodem0011600013861' # apollo4 blue plus serial port
BAUD_RATE = 115200 # Update this to your baud rate

def main():
try:
# Open the serial port
ser = serial.Serial(SERIAL_PORT, BAUD_RATE, timeout=0.01)
print(f"Opened serial port {SERIAL_PORT} at {BAUD_RATE} baud.")

# Give the microcontroller some time to reset
time.sleep(2)

# Continuous loop to alternately send and receive data
while True:
# Send a command to the microcontroller
command = "Hello, MCU!\n"
ser.write(command.encode())
print(f"Sent: {command.strip()}")

# Wait for a response from the microcontroller

try:
if ser.in_waiting > 0: # Check if data is available to read
response = ser.read(256)
if response:
print(f"Received: ", response.decode('utf-8'))
# print(f"Received (raw bytes): {[hex(b) for b in response]}")

else:
print("Received empty response.")
else:
print("No response received.")
except OSError as e:
print(f"Error reading from serial port: {e}")

# Small delay before the next iteration
time.sleep(1)

except serial.SerialException as e:
print(f"Error: {e}")
except OSError as e:
print(f"OS Error: {e}")
finally:
# Close the serial port
if ser.is_open:
ser.close()
print("Closed serial port.")

if __name__ == "__main__":
main()
Loading