Teensyduino USB Serial: Power Consumption Issue

Status
Not open for further replies.

PhilB

Well-known member
I have designed a PCB that uses a T4.1 and communicates with an application running on a PC via Serial USB. When I plug this board into 2 different Windows 10 PCs, it draws 78 mA from one and 110 mA from the other. I believe this is Teensyduino related.

PC A is a 3 year old Win 10 machine. When plugged into it, the board draws 110 mA when it is quiescent (ie, not doing anything, waiting for a command, though there is a 30-40 character status message sent every second)
PC B is a 5 year old Win 10 Machine. When plugged into it, the same board, same software build draws 76 mA when quiescent.

This is with my CNC controller breakout board running grblHAL. In both high and low current cases, grblHAL runs my test suite correctly (and the current draw difference doesn't change when running the tests). I have it set up to monitor USB current so I am always aware of the current draw - see the picture below. This current difference happens if I use the Teensyduino USB. However, using Arduino Serial USB (i.e. calling Serial.begin() in init) I don't get the variation - it always draws the higher current. I build with CPU Speed: 528 MHz and USB type: Serial. So, I think it clear that the lower consumption is something that Teensyduino is doing. I believe both USB ports are USB 2.0.

I would like to understand what is causing machine B to have a lower current draw so I can set it up to always have the lower draw. Any help would be greatly appreciated. I looked at usb.c and usb_serial*.c in cores/teensy4 but didn't see anything obvious. Maybe a VBUS issue?

More info:
grblHAL uses a wrapper around the USB Serial interface to make it easy to port to different HW. Here is the USB wrapper for Teenysduino. Note that usb_serialInit does not explicitly call .begin():
Code:
/*

  usb_serial_pjrc.c - driver code for IMXRT1062 processor (on Teensy 4.0 board) : USB serial port wrapper, PJRC version

  Part of GrblHAL

  Copyright (c) 2018-2020 Terje Io


  Grbl is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  Grbl is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with Grbl.  If not, see <http://www.gnu.org/licenses/>.

*/

//#include "avr/pgmspace.h"
#include "usb_serial.h"

#include "driver.h"

#if USB_SERIAL_GRBL == 2

#define BLOCK_RX_BUFFER_SIZE 20

static stream_block_tx_buffer_t txbuf = {0};
static char rxbuf[BLOCK_RX_BUFFER_SIZE];
static stream_rx_buffer_t usb_rxbuffer, usb_rxbackup;

void usb_serialInit(void)
{
//    usb_serial_configure(); // Done somewhere already - do not call again
    txbuf.s = txbuf.data;
    txbuf.max_length = usb_serial_write_buffer_free(); // 6144
    txbuf.max_length = (txbuf.max_length > BLOCK_TX_BUFFER_SIZE ? BLOCK_TX_BUFFER_SIZE : txbuf.max_length) - 20;

}

//
// Returns number of characters in serial input buffer
//
uint16_t usb_serialRxCount (void)
{
    uint_fast16_t tail = usb_rxbuffer.tail, head = usb_rxbuffer.head;
    return (uint16_t)BUFCOUNT(head, tail, RX_BUFFER_SIZE);
}

//
// Returns number of free characters in serial input buffer
//
uint16_t usb_serialRxFree (void)
{
    uint_fast16_t tail = usb_rxbuffer.tail, head = usb_rxbuffer.head;
    return (uint16_t)((RX_BUFFER_SIZE - 1) - BUFCOUNT(head, tail, RX_BUFFER_SIZE));
}

//
// Flushes the serial input buffer (including the USB buffer)
//
void usb_serialRxFlush (void)
{
    usb_serial_flush_input();
    usb_rxbuffer.tail = usb_rxbuffer.head;
}

//
// Flushes and adds a CAN character to the serial input buffer
//
void usb_serialRxCancel (void)
{
    usb_rxbuffer.data[usb_rxbuffer.head] = CMD_RESET;
    usb_rxbuffer.tail = usb_rxbuffer.head;
    usb_rxbuffer.head = (usb_rxbuffer.tail + 1) & (RX_BUFFER_SIZE - 1);
}

//
// Writes a character to the serial output stream
//
bool usb_serialPutC (const char c)
{
    usb_serial_putchar(c);

    return true;
}

//
// Writes a null terminated string to the serial output stream, blocks if buffer full
//
void usb_serialWriteS (const char *s)
{
    if(*s == '\0')
        return;

    size_t length = strlen(s);

    if((length + txbuf.length) < BLOCK_TX_BUFFER_SIZE) {

        memcpy(txbuf.s, s, length);
        txbuf.length += length;
        txbuf.s += length;

        if(s[length - 1] == ASCII_LF || txbuf.length > txbuf.max_length) {

            size_t txfree;
            txbuf.s = txbuf.data;

            while(txbuf.length) {

                if((txfree = usb_serial_write_buffer_free()) > 10) {

                    length = txfree < txbuf.length ? txfree : txbuf.length;

                    usb_serial_write(txbuf.s, length); //

                    txbuf.length -= length;
                    txbuf.s += length;
                }

                if(txbuf.length && !hal.stream_blocking_callback()) {
                    txbuf.length = 0;
                    txbuf.s = txbuf.data;
                    return;
                }
            }
            txbuf.s = txbuf.data;
        }
    }
}

//
// Writes a null terminated string to the serial output stream followed by EOL, blocks if buffer full
//
void usb_serialWriteLn (const char *s)
{
    usb_serialWriteS(s);
    usb_serialWriteS(ASCII_EOL);
}

//
// Writes a number of characters from string to the serial output stream followed by EOL, blocks if buffer full
//
void usb_serialWrite (const char *s, uint16_t length)
{
    char *ptr = (char *)s;

    while(length--)
        usb_serialPutC(*ptr++);
}

//
// serialGetC - returns -1 if no data available
//
int16_t usb_serialGetC (void)
{
    uint16_t bptr = usb_rxbuffer.tail;

    if(bptr == usb_rxbuffer.head)
        return -1; // no data available else EOF

    char data = usb_rxbuffer.data[bptr++];              // Get next character, increment tmp pointer
    usb_rxbuffer.tail = bptr & (RX_BUFFER_SIZE - 1);    // and update pointer

    return (int16_t)data;
}

// "dummy" version of serialGetC
static int16_t serialGetNull (void)
{
    return -1;
}

bool usb_serialSuspendInput (bool suspend)
{
    if(suspend)
        hal.stream.read = serialGetNull;
    else if(usb_rxbuffer.backup)
        memcpy(&usb_rxbuffer, &usb_rxbackup, sizeof(stream_rx_buffer_t));

    return usb_rxbuffer.tail != usb_rxbuffer.head;
}

//
// This function get called from the systick interrupt handler,
// used here to get characters off the USB serial input stream and buffer
// them for processing by grbl. Real time command characters are stripped out
// and submitted for realtime processing.
//
void usb_execute_realtime (uint_fast16_t state)
{
    char c, *dp;
    int avail, free;

    if((avail = usb_serial_available())) {

        dp = rxbuf;
        free = usb_serialRxFree();
        free = free > BLOCK_RX_BUFFER_SIZE ? BLOCK_RX_BUFFER_SIZE : free;

        avail = usb_serial_read(rxbuf, avail > free ? free : avail);

        while(avail--) {
            c = *dp++;
            if(c == CMD_TOOL_ACK && !usb_rxbuffer.backup) {
                memcpy(&usb_rxbackup, &usb_rxbuffer, sizeof(stream_rx_buffer_t));
                usb_rxbuffer.backup = true;
                usb_rxbuffer.tail = usb_rxbuffer.head;
                hal.stream.read = usb_serialGetC; // restore normal input
            } else if(!hal.stream.enqueue_realtime_command(c)) {
                uint32_t bptr = (usb_rxbuffer.head + 1) & (RX_BUFFER_SIZE - 1); // Get next head pointer
                if(bptr == usb_rxbuffer.tail)                                   // If buffer full
                    usb_rxbuffer.overflow = On;                                 // flag overflow,
                else {
                    usb_rxbuffer.data[usb_rxbuffer.head] = c;                   // else add character data to buffer
                    usb_rxbuffer.head = bptr;                                   // and update pointer
                }
            }
        }
    }
}

#endif

Board Schematic is here.
grblHAL Software is here though it is huge...
more detail about the grblHAL board are here.
 

Attachments

  • IMG_20200707_135910.jpg
    IMG_20200707_135910.jpg
    234.3 KB · Views: 42
A small update (or not...). PC A has USB 3.0 ports but I recall that the front panel ones (which I am using) are 2.0. I could have misremembered that though.

Is USB2 vs 3 a cause of the difference?
 
Status
Not open for further replies.
Back
Top