nrf5340 transfer data with UART and CDC_ACM, know when to add data to UART buffer

I want to transfer a bunch of data over the virtual com port to a PC using the USB port on the nrf5340.  I'm using the CDC ACM sample: https://developer.nordicsemi.com/nRF_Connect_SDK/doc/latest/zephyr/samples/subsys/usb/cdc_acm/README.html

That sample takes a character in and pushes the character back out.  Simple and it works. 

Since I want to dump a bunch of data, I started doing the same uart_fifo_fill() command.  It appears I can only add 1024 bytes to that at a time, which is fine.  That function returns the number of bytes it send (or added to the buffer). 

My question is, how do I know when I can add more data to that buffer?  When can I call that command again.  There were a couple other functions in UART.H and the one when TX was completed is not implemented and the other is "TX buffer can take at least 1 byte of data" but that doesn't seem ideal.  I want to know when I can send 1024 bytes of data again.  

What's the ideal method for pushing a bunch of data through the UART so that it runs as fast as possible and I know when I can push more data into the buffer?

Parents Reply Children
  • Thanks for getting back to me. 

    The example uses:

    uart_irq_callback_set(dev, interrupt_handler);

    Is that different than the uart_callback_set()?  And since I already setup the above callback, do I check for a different event in the same interrupt_handler() function?  Do I use the one you mentioned?  Do I need to setup 2?

  • Hi,

    Ah, yes. I did not check the sample. That use the interrupt driven approach, so in that case uart_irq_callback_set() is used (see intro in the UART API documentation for a brief overview of the different approaches). With this API you don't get an event specifically when a Tx operation is completed, but you will get the callback for any UART interrupt. So in this case you could for instance expand the interrupt_handler() in the sample to check the buffer filling using ring_buf_size_get() every time it is called.

  • Again, I really do appreciate the help and you taking the time to get back to me. 

    Isn't the ring buffer in this example just a place to put the data that comes in the RX line?  It has nothing to do with the TX at all.  Other than in this example we take that and push it into the UART FIFO. 

    My "problem" is that I want to push tons of data out the UART and right now, I don't see a good way to do it.  Or a good way know when the last time I put something into the FIFO of the UART that it's done and can take more.  The uart fifo fill function takes what you send it and at most will send 1024 bytes.  But if I come back and send another 1024 bytes too quickly it replies with "I sent 635" or something.  And when I tested this, it appears that it sends the last 635 of the data that I add to it.  So I can't even try again with the remainder of my buffer. 

    irq tx ready gives you "if the tx buffer can accept at least 1 byte", that doesn't help unless I'm sending data one byte at a time. 

    tx complete says: Note that this function is not useful to check if UART TX can accept more data, use uart_irq_tx_ready() for that.  And in my example even if I wanted to use it, it's not implemented.  Can I do something to make it so that it IS implemented?

    The only way I got this to work is fifo fill and then wait 10ms.  And then do it again monitoring the response from fifo fill so that if it replies with anything less than what I push to it, I know my data transmission failed and I have to wait longer.  It kinda gets the job done, sort of but it's so terrible. 

    Am I going about this all wrong?  Is there a better way to send a ton of data on the UART as fast as possible? 

  • Hi,

    You are right, uart_irq_tx_ready() was what I should have referred to before and not ring_buf_size_get() (will update the post in case other read it in the future). I do not see any other obvious way than what I described before (but with uart_irq_tx_ready()). With that approach, you will not spend too much time polling.

    Is it a problem that you may not be able to write all data at once? I understand it is a bit annoying as the application code must keep track of what is buffered, but that is how this is done by other "users" in the SDK. See for instance the implementation of uart_isr_callback() in the logger.

  • It's not a problem, I have 8 gigabits that I want to transmit (at most, it's a flash chip and I want to dump the memory, yes I know it's gonna take a while).  Slight smile  So I know I have to split it up, and it's gonna be the only job for the micro when this happens so I don't care if it takes 100% of CPU cycles, I just want to minimize the time spent uart-ing. 

    The problem I saw with the uart_irq_tx_ready() is that it says that it returns true if it can take at least 1 byte.  Ok, but what if I want to send 1024 bytes?  Or more than 1, it doesn't tell me how many bytes I can send just that 1 is ok, any more????  Guess?  Does that mean I have to send 1 byte at a time? 

    I quickly checked out the logger example you have, and I'm not sure I understand it, or if it looks like it's any better.  It does look like they keep track of things a bit, but maybe I'm missing something. 

    Thanks again for taking the time to post stuff for me here.

Related