Error USAGE FAULT. How to fix LPUART Non-Blocking function with receiving? #74331
-
Describe the bug device tree DTS
device tree DTSI
main code /*
* Copyright (c) 2018 Intel Corporation.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(net_gptp_sample, LOG_LEVEL_DBG);
#include <zephyr/kernel.h>
#include <errno.h>
#include <zephyr/net/net_core.h>
#include <zephyr/net/net_l2.h>
#include <zephyr/net/net_if.h>
#include <zephyr/net/ethernet.h>
#include <zephyr/net/gptp.h>
#include <zephyr/drivers/gpio.h>
#include "fsl_lpuart.h"
#include <zephyr/drivers/clock_control.h>
#define LED0_NODE DT_ALIAS(led0)
extern void init_testing(void);
static const struct gpio_dt_spec led_green = GPIO_DT_SPEC_GET(LED0_NODE, gpios);
#define LED1_NODE DT_ALIAS(led1)
extern void init_testing(void);
static const struct gpio_dt_spec led_red = GPIO_DT_SPEC_GET(LED1_NODE, gpios);
static struct gptp_phase_dis_cb phase_dis;
/* size of stack area used by each thread */
#define STACKSIZE 1024
/* scheduling priority used by each thread */
#define PRIORITY 7
struct led {
struct gpio_dt_spec spec;
uint8_t num;
};
static const struct led led0 = {
.spec = GPIO_DT_SPEC_GET_OR(LED0_NODE, gpios, {0}),
.num = 0,
};
static const struct led led1 = {
.spec = GPIO_DT_SPEC_GET_OR(LED1_NODE, gpios, {0}),
.num = 1,
};
#if defined(CONFIG_NET_GPTP_VLAN)
/* User data for the interface callback */
struct ud {
struct net_if *first;
struct net_if *second;
struct net_if *third;
};
static void iface_cb(struct net_if *iface, void *user_data)
{
struct ud *ud = user_data;
if (net_if_l2(iface) != &NET_L2_GET_NAME(ETHERNET)) {
return;
}
if (!ud->first) {
ud->first = iface;
return;
}
if (!ud->second) {
ud->second = iface;
return;
}
if (!ud->third) {
ud->third = iface;
return;
}
}
static int setup_iface(struct net_if *iface, const char *ipv6_addr,
const char *ipv4_addr, uint16_t vlan_tag)
{
struct net_if_addr *ifaddr;
struct in_addr addr4;
struct in6_addr addr6;
int ret;
ret = net_eth_vlan_enable(iface, vlan_tag);
if (ret < 0) {
LOG_ERR("Cannot enable VLAN for tag %d (%d)", vlan_tag, ret);
}
if (net_addr_pton(AF_INET6, ipv6_addr, &addr6)) {
LOG_ERR("Invalid address: %s", ipv6_addr);
return -EINVAL;
}
ifaddr = net_if_ipv6_addr_add(iface, &addr6, NET_ADDR_MANUAL, 0);
if (!ifaddr) {
LOG_ERR("Cannot add %s to interface %p", ipv6_addr, iface);
return -EINVAL;
}
if (net_addr_pton(AF_INET, ipv4_addr, &addr4)) {
LOG_ERR("Invalid address: %s", ipv4_addr);
return -EINVAL;
}
ifaddr = net_if_ipv4_addr_add(iface, &addr4, NET_ADDR_MANUAL, 0);
if (!ifaddr) {
LOG_ERR("Cannot add %s to interface %p", ipv4_addr, iface);
return -EINVAL;
}
LOG_DBG("Interface %p VLAN tag %d setup done.", iface, vlan_tag);
return 0;
}
static int init_vlan(void)
{
struct ud ud;
int ret;
(void)memset(&ud, 0, sizeof(ud));
net_if_foreach(iface_cb, &ud);
/* This sample has two VLANs. For the second one we need to manually
* create IP address for this test. But first the VLAN needs to be
* added to the interface so that IPv6 DAD can work properly.
*/
ret = setup_iface(ud.second,
CONFIG_NET_SAMPLE_IFACE2_MY_IPV6_ADDR,
CONFIG_NET_SAMPLE_IFACE2_MY_IPV4_ADDR,
CONFIG_NET_SAMPLE_IFACE2_VLAN_TAG);
if (ret < 0) {
return ret;
}
ret = setup_iface(ud.third,
CONFIG_NET_SAMPLE_IFACE3_MY_IPV6_ADDR,
CONFIG_NET_SAMPLE_IFACE3_MY_IPV4_ADDR,
CONFIG_NET_SAMPLE_IFACE3_VLAN_TAG);
if (ret < 0) {
return ret;
}
return 0;
}
#endif /* CONFIG_NET_GPTP_VLAN */
static void gptp_phase_dis_cb(uint8_t *gm_identity,
uint16_t *time_base,
struct gptp_scaled_ns *last_gm_ph_change,
double *last_gm_freq_change)
{
char output[sizeof("xx:xx:xx:xx:xx:xx:xx:xx")];
static uint8_t id[8];
if (memcmp(id, gm_identity, sizeof(id))) {
memcpy(id, gm_identity, sizeof(id));
LOG_DBG("GM %s last phase %d.%" PRId64 "",
gptp_sprint_clock_id(gm_identity, output, sizeof(output)),
last_gm_ph_change->high,
last_gm_ph_change->low);
}
}
static int init_app(void)
{
#if defined(CONFIG_NET_GPTP_VLAN)
if (init_vlan() < 0) {
LOG_ERR("Cannot setup VLAN");
}
#endif
gptp_register_phase_dis_cb(&phase_dis, gptp_phase_dis_cb);
return 0;
}
void blink(const struct led *led, uint32_t sleep_ms, uint32_t id)
{
const struct gpio_dt_spec *spec = &led->spec;
int cnt = 0;
gpio_pin_configure_dt(spec, GPIO_OUTPUT);
while (1) {
gpio_pin_set(spec->port, spec->pin, cnt % 2);
k_msleep(sleep_ms);
cnt++;
}
}
void blink0(void)
{
blink(&led0, 100, 0);
}
void blink1(void)
{
blink(&led1, 500, 1);
}
#define LPUART3_BASE (0x4018C000u)
/** Peripheral LPUART3 base pointer */
#define LPUART3 ((LPUART_Type *)LPUART3_BASE)
#define BUFF_LEN 16
#define UART_NODE DT_NODELABEL(lpuart2)
struct rt1060_lpuart_config {
LPUART_Type *base;
const struct device *clock_dev;
clock_control_subsys_t clock_subsys;
clock_ip_name_t clock_ip_name;
uint32_t clock_ip_src;
uint32_t baud_rate;
uint8_t hw_flow_control;
#ifdef CONFIG_UART_INTERRUPT_DRIVEN
void (*irq_config_func)(const struct device *dev);
#endif
const struct pinctrl_dev_config *pincfg;
};
void uart_polling_get(void)
{
lpuart_transfer_t xfer;
lpuart_handle_t lpuart_handle;
lpuart_config_t lpuart_config;
char buf[16];
xfer.data = buf;
xfer.dataSize = BUFF_LEN;
size_t receivedBytes = 0;
uint32_t clock_freq;
static const struct device *const uart_dev = DEVICE_DT_GET(UART_NODE);
const struct rt1060_lpuart_config *clock_config = dev->config;
device_is_ready(clock_config->clock_dev);
clock_control_get_rate(clock_config->clock_dev, clock_config->clock_subsys, &clock_freq);
LPUART_GetDefaultConfig(&lpuart_config);
lpuart_config.parityMode = kLPUART_ParityEven;
lpuart_config.dataBitsCount = kLPUART_EightDataBits;
lpuart_config.enableTx = true;
lpuart_config.enableRx = true;
(void)LPUART_Init(LPUART3, &lpuart_config, clock_freq);
while(1){
LPUART_TransferReceiveNonBlocking(LPUART3, &lpuart_handle, &xfer, &receivedBytes);
k_msleep(100);
}
}
int main(void)
{
if (!gpio_is_ready_dt(&led_green) && !gpio_is_ready_dt(&led_red)) {
return 0;
}
init_app();
init_testing();
return 0;
}
K_THREAD_DEFINE(blink0_id, STACKSIZE, blink0, NULL, NULL, NULL,
7, 0, 0);
K_THREAD_DEFINE(blink1_id, STACKSIZE, blink1, NULL, NULL, NULL,
7, 0, 0);
K_THREAD_DEFINE(uart_polling_get_id, STACKSIZE, uart_polling_get, NULL, NULL, NULL,
119, 0, 0); console log
|
Beta Was this translation helpful? Give feedback.
Replies: 5 comments
-
A first piece of the puzzle is that you'll first need to create the handle before you use it: You can add a callback instead of NULL too. The issue what I'm running into is that for a device which is active in Zephyr, the IRQ is claimed by the driver and the LPUART_... code is disentangled. |
Beta Was this translation helpful? Give feedback.
-
I managed to get at least something working: (I'm using LPUART6. Update accordingly)
|
Beta Was this translation helpful? Give feedback.
-
Hi @SynchronicIT , Thanks your advise and sample code. I try and modify it with some difference, but I still don't get anything from LPUART2. code #define LPUART2_BASE (0x40188000u)
/** Peripheral LPUART3 base pointer */
#define LPUART2 ((LPUART_Type *)LPUART2_BASE)
#define RX2_RING_BUFFER_SIZE 256U
uint8_t buf[256];
uint8_t sniffer_buf[256];
void LPUART_UserCallback(LPUART_Type *base, lpuart_handle_t *handle, status_t status, void *userData)
{
if (kStatus_LPUART_TxIdle == status)
{
printf("TX Idle");
} else if (kStatus_LPUART_RxIdle == status)
{
printf("RX Idle");
} else {
printf("UART status = %d", status);
}
}
int main (void)
{
CLOCK_EnableClock(kCLOCK_Iomuxc);
#if DT_NODE_HAS_STATUS(DT_NODELABEL(lpuart2), okay) && CONFIG_SERIAL
printf("config works\n");
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_02_LPUART2_TX, 0);
IOMUXC_SetPinMux(IOMUXC_GPIO_AD_B1_03_LPUART2_RX, 0);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_02_LPUART2_TX, 0x10B0U);
IOMUXC_SetPinConfig(IOMUXC_GPIO_AD_B1_03_LPUART2_RX, 0x10B0U);
#endif
// IRQ_CONNECT(21, 0, __LPUART2_IRQHandler, NULL, 0);
irq_enable(21);
lpuart_transfer_t xfer;
lpuart_handle_t lpuart_handle;
lpuart_config_t lpuart_config;
xfer.rxData = buf;
xfer.dataSize = sizeof(buf);
size_t receivedBytes = 0;
uint32_t clock_freq;
clock_freq = 80000000;
LPUART_GetDefaultConfig(&lpuart_config);
lpuart_config.baudRate_Bps = 115200U;
lpuart_config.parityMode = kLPUART_ParityEven;
lpuart_config.dataBitsCount = kLPUART_EightDataBits;
lpuart_config.enableTx = true;
lpuart_config.enableRx = true;
(void)LPUART_Init(LPUART2, &lpuart_config, clock_freq); //dev_config->base
printf("freq = %u\n", clock_freq);
LPUART_TransferCreateHandle(LPUART2, &lpuart_handle, LPUART_UserCallback, NULL);
LPUART_TransferStartRingBuffer(LPUART2, &lpuart_handle, sniffer_buf, sizeof(sniffer_buf));
// LPUART_EnableInterrupts(LPUART2, kLPUART_RxDataRegFullInterruptEnable);
// EnableIRQ(LPUART2_IRQn);
while(1) {
status_t rv = LPUART_TransferReceiveNonBlocking(LPUART2, &lpuart_handle, &xfer, &receivedBytes);
printf("transfer[%d] -> recv: %u\n", rv, receivedBytes);
printf("xfer:%c%c%c%c%c%c%c%c%c%c\n", buf[0], buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7],buf[8],buf[9]);
k_msleep(300);
}
} debug trace
|
Beta Was this translation helpful? Give feedback.
-
@YMont is this still an issue? |
Beta Was this translation helpful? Give feedback.
-
Hi @YMont , Zephyr provides a UART driver to work across different hardware platforms. The NXP platforms support this driver. The MCUXpresso SDK drivers are used at the low-level to control the hardware. But in Zephyr, a shim layer is provided to translate Zephyr's driver APIs to the MCUXpresso SDK APIs. To learn more, see this webinar Application Portability Made Easy With Zephyr OS and NXP, or this blog. Enabling LPUART2 in the devicetree is using the Zephyr and the shim driver. The startup code will initialize this driver before I recommend you use one method or the other. One option is to use the Zephyr UART APIs in your app. This is how the Zephyr UART examples work, and you can reference them. Or the other option is to only use the MCUXpresso SDK APIs in your app. In that case, I recommend you disable the UART in your devicetree, and if not using the Zephyr driver then deselect These GitHub issues are used to track bugs in the repo or feature requests. Since there is no evidence here of a bug, I am moving this topic to a Discussion. Best regards |
Beta Was this translation helpful? Give feedback.
Hi @YMont ,
I think this is an application issue. And reviewing the code you shared, I see you are initializing and controlling the UART using the MCUXpresso SDK driver APIs. But from your devicetree you also have the Zephyr driver enabled for that same peripheral. This seems to be a conflict, with two sets of drivers used for the same peripheral.
Zephyr provides a UART driver to work across different hardware platforms. The NXP platforms support this driver. The MCUXpresso SDK drivers are used at the low-level to control the hardware. But in Zephyr, a shim layer is provided to translate Zephyr's driver APIs to the MCUXpresso SDK APIs. To learn more, see this webinar Application Portabili…