Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

board = ATmega328PB causes incorrect linkage #5066

Open
1 task
norventa opened this issue Jan 15, 2025 · 0 comments
Open
1 task

board = ATmega328PB causes incorrect linkage #5066

norventa opened this issue Jan 15, 2025 · 0 comments

Comments

@norventa
Copy link

What kind of issue is this?

  • Development Platform or Board.
    All issues (building, uploading, adding new boards, etc.) related to PlatformIO development platforms
    should be reported to appropriate repository related to your hardware
    https://github.com/topics/platformio-platform

Configuration

Operating system:
Windows ATmega development using vscode and platformio extension.

PlatformIO Version (platformio --version):
3.3.4

Description of problem

Using board = ATmega328PB in platformio.ini causes incorrect linkage to USART_UDRE_vect.
All compiles ok but gives warning that USART_UDRE_vect is misspelt. When running program on a ATmega328PB the interrupt handler misbehaves. Using board = ATmega328P in platformio.ini all works fine.

Steps to Reproduce

  1. Create an AVR project.
  2. Copy the platformio.ini file and cpp code below.
  3. Build, upload and run.

Actual Results

There will be a series of blinks shown on the LED but no long blinks.

Expected Results

Thre should be two long blinks after the short ones.

If problems with PlatformIO Build System:

The content of platformio.ini:

Insert here...
; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:ATmega328PB]
platform = atmelavr
board = ATmega328PB
board_build.f_cpu = 16000000L
platform_packages = platformio/tool-avrdude@^1.70200.0
build_type = debug
upload_protocol = custom
upload_port = usb
upload_flags = 
    -C
    ${platformio.packages_dir}/tool-avrdude/avrdude.conf
    -p
    ATmega328PB
    -P
    usb
    -c
    avrisp2
upload_command = avrdude $UPLOAD_FLAGS -U flash:w:$SOURCE:i

Source file to reproduce issue:

#include <string.h>
#include <util/atomic.h>


// The ring buffer:
//
#define RING_BUFFER_SIZE 256


class DRing
{
protected:
    uint8_t m_au08Buffer[RING_BUFFER_SIZE];
    volatile uint8_t m_u08Head;
    volatile uint8_t m_u08Tail;
    volatile uint16_t m_u16Length;

public:
    DRing():
        m_u08Head(0),
        m_u08Tail(0),
        m_u16Length(0)
    {
    }

    bool PushISR(uint8_t u08Byte)
    {
        if (m_u16Length >= RING_BUFFER_SIZE)
            return false;

        m_au08Buffer[m_u08Head++] = u08Byte;
        ++m_u16Length;
        return true;
    }

    bool PushISR(const uint8_t *pu08Bytes, uint8_t u08Length)
    {
        if (m_u16Length + u08Length > RING_BUFFER_SIZE)
            return false;

        while (u08Length > 0)
        {
            m_au08Buffer[m_u08Head++] = *pu08Bytes++;
            ++m_u16Length;
            --u08Length;
        }

        return true;
    }

    bool PullISR(uint8_t &ru08Byte)
    {
        if (m_u16Length == 0)
            return false;

        ru08Byte = m_au08Buffer[m_u08Tail++];
        --m_u16Length;
        return true;
    }
};


static DRing s_TxRing;


// Blinks the LED for debug.
//
#define LED_DDR  DDRB
#define LED_PORT PORTB
#define LED_BIT  5 // D13 (LED)


static uint16_t s_u16NumBlinks;


// Good for upto 2s.
//
static void
delayMS(uint32_t ms)
{
    uint32_t count = (F_CPU / 1000 * ms) / 12;

    for (uint32_t u = 0; u < count; ++u)
        __asm__ volatile("nop\n\t");
}


void
dot()
{
    ++s_u16NumBlinks;

    for (uint16_t u = 0; u < s_u16NumBlinks; ++u)
    {
        LED_PORT |= 1 << LED_BIT;
        delayMS(250);
        LED_PORT &= ~(1 << LED_BIT);
        delayMS(250);
    }

    delayMS(2000);
}


void
dash()
{
    LED_PORT |= 1 << LED_BIT;
    delayMS(1000);
    LED_PORT &= ~(1 << LED_BIT);
    delayMS(2000);
    s_u16NumBlinks = 0;
}


// The serial stuff:
//
#define DDR      DDRD
#define TX_BIT   1
#define BAUDRATE 57600UL


// Called when the UART is ready to transmit the next byte.
//
ISR(USART_UDRE_vect, ISR_BLOCK)
{
    // These won't he seen.
    //
    dash();
    dash();

    uint8_t byte;

    if (!s_TxRing.PullISR(byte))
    {
        // Disable this interrupt.
        //
        UCSR0B &= ~_BV(UDRIE0);
    }
    else
    {
        // Start transmission
        //
        UDR0 = byte;
    }
}


static void
setBaud()
{
    uint16_t UBRR_VAL     = (unsigned int)(F_CPU / (16.0 * BAUDRATE) + 0.5) - 1;
    uint16_t UBRR_VAL_U2X = (unsigned int)(F_CPU / (8.0 * BAUDRATE) + 0.5) - 1;

    double BAUD     = F_CPU / (16 * (UBRR_VAL + 1));
    double BAUD_U2X = F_CPU / (8 * (UBRR_VAL_U2X + 1));

    double ERROR     = (BAUD / BAUDRATE) - 1;
    double ERROR_U2X = (BAUD_U2X / BAUDRATE) - 1;

    if (ERROR < 0)
        ERROR *= -1.0;

    if (ERROR_U2X < 0)
        ERROR_U2X *= -1.0;

    if (ERROR <= ERROR_U2X)
    {
        UCSR0A &= ~_BV(U2X0);
        UBRR0 = UBRR_VAL;
    }
    else
    {
        UCSR0A |= _BV(U2X0);
        UBRR0 = UBRR_VAL_U2X;
    }
}


static void
putBytes(const uint8_t *pu08Data, uint8_t u08DataLen)
{
    dot();

    ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
    {
        if (!s_TxRing.PushISR(pu08Data, u08DataLen))
            return;

        // Enable the transmit buffer empty interrupt.
        //
        UCSR0B |= _BV(UDRIE0);

        // See if transmit buffer is empty.
        //
        if ((UCSR0A & _BV(UDRE0)) == _BV(UDRE0))
        {
            uint8_t byte;

            if (s_TxRing.PullISR(byte))
            {
                // The first byte will be sent ok as it isn't done by the interrrupt function.
                //
                UDR0 = byte;
                dot();
            }
        }

        // *** This will allow interrupts. ***
        //
        dot();
    }

    dot();

    // At this point there should be dot, dot, dot, dot but there won't be.
}


void
Init()
{
    // Enable USART transmitter.
    //
    UCSR0B = _BV(TXEN0);

    // Set frame format: asynchronous, 8 data bits, no parity, 1 stop bit
    //
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);

    // Do this after UCSRC is set above.
    //
    setBaud();

    // Set data direction: 0 for i/p, 1 for o/p.
    //
    DDR |= _BV(TX_BIT);
}


void
Write(const char *pszStr)
{
    if (pszStr == 0 || *pszStr == 0)
        return;

    int len = strlen(pszStr);

    putBytes((const uint8_t *)pszStr, len);
}


int
main()
{
    LED_DDR |= 1 << LED_BIT;
    Init();
    sei();
    Write("KilnDAC\r\n");

    while (true)
    {
    }
}```

### Additional info
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant