Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 2 of 2

Thread: Teensyduino USB Serial: Power Consumption Issue

  1. #1
    Senior Member
    Join Date
    Mar 2016
    Posts
    198

    Teensyduino USB Serial: Power Consumption Issue

    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.
    Attached Thumbnails Attached Thumbnails Click image for larger version. 

Name:	IMG_20200707_135910.jpg 
Views:	3 
Size:	234.3 KB 
ID:	20910  

  2. #2
    Senior Member
    Join Date
    Mar 2016
    Posts
    198
    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?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •