Unable to read more the 1 Byte using ATSAMD21 USB CDC

Go To Last Post
27 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My application is to receive data from java (GUI) application,and send it back to the GUI.

The reading of the received data is creating the issue. It is only able to read one byte.

I can send other data it is not a problem. So i'm assuming that the read call is creating issue.

 

->I'm working using atmel studio 7.0, the code which i'm using is USB  Communication Device Class (CDC)  for ATSAMD21.

->The code which i'm using  and the documentation link is here Microchip® Advanced Software Framework.

 

Code snippet:

   

 

static void usart_rx_callback(struct usart_module *const module)
{
	/* Data received */
	ui_com_tx_start();

	/* Transfer UART RX fifo to CDC TX */
if (!udi_cdc_is_tx_ready()) {
		///* Fifo full */
		udi_cdc_signal_overrun();
		ui_com_overflow();
	} else {
		udi_cdc_write_buf(&rx_data, 10);  //Writes a RAM buffer on CDC line. 
	}
	ui_com_tx_stop();
	usart_read_buffer_job(&usart_module_edbg, &rx_data, 10);//Asynchronous buffer read.Sets up the driver to read from the USART to a given buffer.
	                                                        // If registered and enabled, a callback function will be called.
	                                                                
	return;
}
void uart_rx_notify(uint8_t port)
{


UNUSED(port);
if (!tx_callback_flag) {
/* Transmit first data */
ui_com_rx_start();
usart_enable_callback(&usart_module_edbg, USART_CALLBACK_BUFFER_TRANSMITTED);
tx_data = udi_cdc_getc();                                                    //Waits and gets a value on CDC line & read
rx_data=tx_data;
udi_cdc_putc(rx_data);
usart_write_buffer_job(&usart_module_edbg, &tx_data, 10);           //rx_data    Pointer to data to be received
 }
} 

Please help me with this issue . Any help will be appreciated.

 

Thanks in Advance.

This topic has a solution.
Last Edited: Mon. Dec 10, 2018 - 12:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The example you have linked has this

The example is a bridge between a USART from the main MCU and the USB CDC interface.

This is not a common use case for CDC and is likely causing some confusion. Probably you should be using only the USB CDC and remove everything relating to the USART. There is no example project like this for D21 but there is one for R21 called "USB Standard I/O (stdio) example" which should be easy enough to convert.

 

Or if you are in fact running this in a board where there is a USART hardwired (for example like the EDBG connection in SAMD21 XPlained Pro) then use only the USART (like any of the USART quick start example projects).

/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

-My application is to read the data coming from host using Target USB port & Send the exact data back through Target USB port .

 

- I can send whatever data i want. So sending is not a problem.

-The receiving of multiple bytes only creating issue I cant read more that one byte of data.

 

-For sending and receiving i'm using the same Target USB port .

- EDBG UART port i'm using only for debugging.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The uart seems way to involved to be "only for debugging", why for example is everything happening in usart_rx_callback and uart_rx_notify?

Given what you describe is the purpose I would suggest you try the  "USB Standard I/O (stdio) example" , it basically has this main:

    /* Call a local utility routine to initialize C-Library Standard I/O over
     * a USB CDC protocol. Tunable parameters in a conf_usb.h file must be
     * supplied to configure the USB device correctly.
     */
    stdio_usb_init();

    // Get and echo characters forever.

    uint8_t ch;

    while (true) {

        scanf("%c",&ch); // get one input character

        if (ch) {
            printf("%c",ch); // echo to output
        }
    }

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This call back will call after the respective transfers  complete. I have given you the link for the code above can you please check the file i'm attaching below and check.

 

 

/**
 * \file
 *
 * \brief UART functions
 *
 * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries.
 *
 * \asf_license_start
 *
 * \page License
 *
 * Subject to your compliance with these terms, you may use Microchip
 * software and any derivatives exclusively with Microchip products.
 * It is your responsibility to comply with third party license terms applicable
 * to your use of third party software (including open source software) that
 * may accompany Microchip software.
 *
 * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE,
 * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY,
 * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE
 * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL
 * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE
 * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE
 * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
 * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY
 * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
 * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.
 *
 * \asf_license_stop
 *
 */
/*
 * Support and FAQ: visit <a href="https://www.microchip.com/support/">Microchip Support</a>
 */

#include <asf.h>
#include "conf_example.h"
#include "uart.h"
#include "main.h"
#include "ui.h"

/* Structure for USART module connected to EDBG */
struct usart_module usart_module_edbg;

/* Structure for USART parameter configuration */
struct usart_config usart_conf;

/* Data for EDBG communication */
static uint8_t tx_data;
static uint8_t rx_data;

/* USART TX callback flag */
static volatile uint8_t tx_callback_flag = 0;

/**
 * \internal
 * \brief USART interrupt callback function
 *
 * Called by USART driver when transmit is complete.
 *
 * * \param module USART module causing the interrupt (not used)
 */
static void usart_tx_callback(struct usart_module *const module)
{
    tx_callback_flag = 1;
    /* Data ready to be sent */
    if (udi_cdc_is_rx_ready()) {
        /* Transmit next data */
        ui_com_rx_start();
        tx_data = udi_cdc_getc();
        //udi_cdc_write_buf(tx_buff, 10);
        usart_write_buffer_job(&usart_module_edbg, &tx_data, 10);
    } else {
        /* Fifo empty then Stop UART transmission */
        usart_disable_callback(&usart_module_edbg, USART_CALLBACK_BUFFER_TRANSMITTED);
        ui_com_rx_stop();
    }
    tx_callback_flag = 0;
}

/**
 * \internal
 * \brief USART interrupt callback function
 *
 * Called by USART driver when receiving is complete.
 *
 * * \param module USART module causing the interrupt (not used)
 */
static void usart_rx_callback(struct usart_module *const module)
{
    /* Data received */
    ui_com_tx_start();

    /* Transfer UART RX fifo to CDC TX */
if (!udi_cdc_is_tx_ready()) {
        ///* Fifo full */
        udi_cdc_signal_overrun();
        ui_com_overflow();
    } else {
        //udi_cdc_putc(rx_data);
        udi_cdc_write_buf(&rx_data, 10);  //Writes a RAM buffer on CDC line. 
        
    }

    ui_com_tx_stop();

    usart_read_buffer_job(&usart_module_edbg, &rx_data, 10);//Asynchronous buffer read.Sets up the driver to read from the USART to a given buffer.

                                                                    // If registered and enabled, a callback function will be called.

    return;
}

void uart_rx_notify(uint8_t port)   //CALLED by inface when cdc rec data
{
    UNUSED(port);
    if (!tx_callback_flag) {
        /* Transmit first data */
        ui_com_rx_start();
        usart_enable_callback(&usart_module_edbg, USART_CALLBACK_BUFFER_TRANSMITTED);
        tx_data = udi_cdc_getc();         //Waits and gets a value on CDC line & read
        rx_data=tx_data;
          udi_cdc_putc(rx_data);    //rx_data    Pointer to data to be received -act
        
        usart_write_buffer_job(&usart_module_edbg, &tx_data, 10);
    }
}

void uart_config(uint8_t port,usb_cdc_line_coding_t *cfg)
{
    UNUSED(port);
    /* Configure USART for unit test output */
    usart_get_config_defaults(&usart_conf);
    usart_conf.generator_source = GCLK_GENERATOR_3;

    switch (cfg->bCharFormat) {
    case CDC_STOP_BITS_2:
        usart_conf.stopbits = USART_STOPBITS_2;
        break;

    case CDC_STOP_BITS_1_5:
        usart_conf.stopbits = USART_STOPBITS_1;
        break;

    case CDC_STOP_BITS_1:
    default:
        /* Default stop bit = 1 stop bit */
        usart_conf.stopbits = USART_STOPBITS_1;
        break;
    }

    switch (cfg->bParityType) {
    case CDC_PAR_EVEN:
        usart_conf.parity = USART_PARITY_EVEN;
        break;

    case CDC_PAR_ODD:
        usart_conf.parity = USART_PARITY_ODD;
        break;

    case CDC_PAR_MARK:
        usart_conf.parity = USART_PARITY_NONE;
        break;

    case CDC_PAR_SPACE:
        usart_conf.parity = USART_PARITY_NONE;
        break;

    case CDC_PAR_NONE:
    default:
        usart_conf.parity = USART_PARITY_NONE;
        break;
    }

    switch(cfg->bDataBits) {
    case 5:
        usart_conf.character_size = USART_CHARACTER_SIZE_5BIT;
        break;
    case 6:
        usart_conf.character_size = USART_CHARACTER_SIZE_6BIT;
        break;
    case 7:
        usart_conf.character_size = USART_CHARACTER_SIZE_7BIT;
        break;
    case 8:
    default:
        usart_conf.character_size = USART_CHARACTER_SIZE_8BIT;
        break;
    }

    /* Options for USART. */
    usart_conf.baudrate = LE32_TO_CPU(cfg->dwDTERate);
    usart_conf.mux_setting = CONF_USART_MUX_SETTING;
    usart_conf.pinmux_pad0 = CONF_USART_PINMUX_PAD0;
    usart_conf.pinmux_pad1 = CONF_USART_PINMUX_PAD1;
    usart_conf.pinmux_pad2 = CONF_USART_PINMUX_PAD2;
    usart_conf.pinmux_pad3 = CONF_USART_PINMUX_PAD3;
    usart_disable(&usart_module_edbg);
    usart_init(&usart_module_edbg, CONF_USART_BASE, &usart_conf);
    usart_enable(&usart_module_edbg);

    /* Enable interrupts */
    usart_register_callback(&usart_module_edbg, usart_tx_callback,
            USART_CALLBACK_BUFFER_TRANSMITTED);
    usart_enable_callback(&usart_module_edbg, USART_CALLBACK_BUFFER_TRANSMITTED);
    usart_register_callback(&usart_module_edbg, usart_rx_callback,
            USART_CALLBACK_BUFFER_RECEIVED);
    usart_enable_callback(&usart_module_edbg, USART_CALLBACK_BUFFER_RECEIVED);
    usart_read_buffer_job(&usart_module_edbg, &rx_data, 10);
}

void uart_open(uint8_t port)
{
    UNUSED(port);

    usart_enable(&usart_module_edbg);
}

void uart_close(uint8_t port)
{
    UNUSED(port);
    /* Close RS232 communication */
    usart_disable(&usart_module_edbg);
}
 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well that seems to work as long as I don't type in the wrong (the EDBG) terminal, the rx part there has problems starting with this:

usart_read_buffer_job(&usart_module_edbg, &rx_data, 10);

You don't have a buffer for 10 characters, just for 1. That callback seems pretty useless anyway. 

 

Similar but less destructive when you send to the EDBG:

usart_write_buffer_job(&usart_module_edbg, &tx_data, 10);

You are sending one actual character and 9 whatever trash.

/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

hi,

 

    Can you help me with how can i fix this issue? what changes i need to make?

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The main part is working, just remove the EDBG debug stuff (at least the usart_rx_callback). And change 10 -> 1.

/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

IF i change that to one how can i receive more that one byte at a time?

Can you tell me where i need to change in this code?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You are already receiving and sending back only one byte at a time here:

tx_data = udi_cdc_getc();                                                    //Waits and gets a value on CDC line & read
rx_data=tx_data;
udi_cdc_putc(rx_data);

The usart stuff you said is only for debugging, what is it that you need to receive there? 

/Lars

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm connecting the TARGET USB PORT to the host and DEBUG PORT to the machine where the atmel studio is running.

The host is sending me data and i'm trying to send it back.  I'm not that much clear with the code flow and all the stuff. I can read and write one byte .

why i cant do it for multiple bytes?

 

My requirement is to receive more that one byte. Can you point out  the changes which i need to make to read more than one byte of data. 

 

 

 

 

Last Edited: Wed. Dec 5, 2018 - 10:48 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

As mentioned the target usb part is working fine when I test it, you are already sending back the data received here

tx_data = udi_cdc_getc();                                                    //Waits and gets a value on CDC line & read
rx_data=tx_data;
udi_cdc_putc(rx_data);

If this is not what you need the program to do then explain.

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm also do testing here i can also send and receive one byte.

Why cant i do it for multiple bytes?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I will just explain what I tested:

1. On PC connect target USB COM port to a terminal program A

2. On PC connect EDBG COM port to a terminal program B

3. Type input in A, every character is echoed back in A hence receiving and sending of multiple characters is working.

You must be doing a different test.

/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

In my case the host is sending a string "12345" .

The host is sending it 5  times i'm able to read 5 times . The issue is i'm only reading "1"  5  times rest of the string "2345" is missing.

 

I'm attaching the logs i'm getting from the host side this may help you to understand the problem.

 

 

byteArr55-->12345- Data from host to device.

received data ->1-Data get back from device

 

 

libusb initialised
handle-->libusb device handle 0x7ff84017f870
device found

count-1
byteArr55-->12345

5-->bytes sent to device
read00
capacity-->64
1 bytes read from device
received data ->1

count-2
byteArr55-->12345

5-->bytes sent to device
read00
capacity-->64
1 bytes read from device
received data ->

count-3
byteArr55-->12345

5-->bytes sent to device
read00
capacity-->64
1 bytes read from device
received data ->1

count-4
byteArr55-->12345

5-->bytes sent to device
read00
capacity-->64
1 bytes read from device
received data ->1

count-5
byteArr55-->12345
10-->bytes sent to device
read00
capacity-->64
1 bytes read from device
received data ->1

 

This is my issue.Please check

Last Edited: Wed. Dec 5, 2018 - 11:45 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't think you can expect a uart_rx_notify for every byte, you might need a loop to extract all currently available rx data.

        while(udi_cdc_is_rx_ready()) {
            tx_data = udi_cdc_getc();         //Waits and gets a value on CDC line & read
            rx_data=tx_data;
            udi_cdc_putc(rx_data);    //rx_data    Pointer to data to be received -act
        }      

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I don't want to notify after each byte . After filling the buffer completely calling call back function is enough. Can you suggest me a change. And send me the code?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry I don't understand, the suggested change is above, it is to deal with the fact that you don't get a uart_rx_notify for every byte received.

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Here the functions which i'm using

udi_cdc_getc(); & 
 udi_cdc_putc()

0nly can read and write one byte of data at a time is there any alternatives fo fixing this issue by another read and write calls?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I know the functions, notice I added a loop around them, this is to get all bytes out of the USB buffer.

Please tell me you have at least tried this:

        while(udi_cdc_is_rx_ready()) {
            tx_data = udi_cdc_getc();         //Waits and gets a value on CDC line & read
            rx_data=tx_data;
            udi_cdc_putc(rx_data);    //rx_data    Pointer to data to be received -act
        }      

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There are other functions that can work better for you, check the doc (or the .h file):

udi_cdc_get_nb_received_data,  udi_cdc_read_buf

/Lars

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi  Lajon ;

Thank you for the   fix you suggested it is working now. I can send back all the data which is from the host.

   while(udi_cdc_is_rx_ready()) {
            tx_data = udi_cdc_getc();         //Waits and gets a value on CDC line & read
            rx_data=tx_data;
            udi_cdc_putc(rx_data);    //rx_data    Pointer to data to be received -act
        }      

I have one more doubt to ask the functions udi_cdc_getc() & udi_cdc_putc() is only for read & write one byte of data.

How it is reading the whole string from the host?

Please suggest me a answer for my doubt.

 

Thank you for your support.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes the mentioned udi_cdc_read_buf might work but I don't think there is any guarantee the strings sent from the host arrive so that you always get them one at a time from udi_cdc_read_buf. For this reason it's good to have some way to sync, could be as simple as collecting in your own buffer until you receive a '\n'.

/Lars

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Lajon ,

    udi_cdc_getc() & udi_cdc_putc() is only for read & write one byte of data.  From the fix you suggested i can receive the all string from the host by using the same functions Can you explain me how it happens?

 

Thanks;

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

There is buffering in the USB implementation (both host and target), on the host "12345" fits in a message and is sent, on target you get only one uart_rx_notify but in fact the full message is available. You can check how many bytes arrived with  udi_cdc_get_nb_received_data , and you can read out this many bytes with one call of udi_cdc_read_buf.

/Lars

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi Lajon ;

 

 

    I tried the change by using  udi_cdc_read_buf it is running fine. I have one doubt about this call please look on to it

 

   SNIPPET 1:


void uart_rx_notify(uint8_t port)//working
{
 while(udi_cdc_is_rx_ready()) {
		        udi_cdc_read_buf(&tx_data, 1);
			memcpy(rx_data,tx_data,sizeof(tx_data));
			udi_cdc_write_buf(&rx_data, 1);
	 }                                                                        

}

If i used this code snippet i'm getting the desired result.

 

 udi_cdc_read_buf(void * buf,iram_size_t size )	

Parameters

buf Values read
size Number of value read

 

If i changed the code like this it is not working:

 

SNIPPET 2:

void uart_rx_notify(uint8_t port)//working
{
 while(udi_cdc_is_rx_ready()) {
		        udi_cdc_read_buf(&tx_data, 5);
			memcpy(rx_data,tx_data,sizeof(tx_data));
			udi_cdc_write_buf(&rx_data, 5);
	 }                                                                        

}

Here i changed the second parameter "size" values to read from 1 to 5. The call. is not reading any data.

In both case i'm sending same string "12345" why the snippet 1 is working & 2 is not?

In the documentation it is mentioned the second parameter is the size to read. Why it happens?

Could  you help me with this?

 

Thanks,

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The udi_cdc_read_buf call will hang (wait for more data) if what you ask for is not available, not sure if this is the problem but don''t read more than what you get from udi_cdc_get_nb_received_data  or you can use udi_cdc_read_no_polling.

 

        const iram_size_t n_rec = udi_cdc_get_nb_received_data();
        uint8_t buf[n_rec];
        udi_cdc_read_buf(buf, n_rec);
        udi_cdc_write_buf(buf, n_rec);

or with a fixed size buffer

        uint8_t buf[64];
        const iram_size_t n_rec = udi_cdc_read_no_polling(buf, sizeof(buf));
        udi_cdc_write_buf(buf, n_rec);	

/Lars