Search code examples
cvisual-studio-codeintellisenseavr

Why does IntelliSense say it cannot find DDRB definition when I added it to json and it can even let me peek the definition? Visual Studio Code


I have this simply blinky.c code for AVR microcontrollers. It compiles and run no problem. But Intellisense in my vscode is going kinda crazy

#define F_CPU 16000000UL
#define LED_PIN 0

#include <avr/io.h>
#include <util/delay.h>

void main()
{
    DDRB |= (1 << LED_PIN);
    while(1)
    {
        PORTB ^= (1 << LED_PIN);
        _delay_ms(500);
    }
}

First I edited the json to add the needed paths:

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "/usr/avr/include",
                "/usr/avr/include/avr"
            ],
            "defines": [],
            "compilerPath": "/usr/bin/gcc",
            "cStandard": "c11",
            "cppStandard": "c++14",
            "intelliSenseMode": "gcc-x86",
            "compilerArgs": [
                "-Wall "
            ]
        }
    ],
    "version": 4
}

And it sees the functions etc, all but DDRB and PORTB:

IntellisenseError

But when I go to "Go to definition" it even lets me see it. So how come it gives me this IntelliSense error?

enter image description here

To be clear Im on Linux right now (Manjaro). I have installed all the needed libs for avrs thru pamac and they work.


Solution

  • Okay, I found a solution. It is caused by the internals of the avr/io.h files. It includes a certain file with definitions based on #define of a given microcontroller in the source code. So when I do not specify the controller it won't #include it in io.h therefor it is not visible to IntelliSense, but compilation can see it because I specify it. So in order to make io.h include definitions we need. We have to tell it which controller we will be using. Like that:

    #define __AVR_ATmega328P__
    

    So that now my code looks like this:

    #define F_CPU 16000000UL
    #define LED_PIN 0
    #define __AVR_ATmega328P__
    
    
    #include <avr/io.h>
    #include <util/delay.h>
    
    void main()
    {
        DDRB |= (1 << LED_PIN);
        while(1)
        {
            PORTB ^= (1 << LED_PIN);
            _delay_ms(500);
        }
    }
    

    You can clearly see it when you look up the io.h file:

    #if defined (__AVR_AT94K__)
    #  include <avr/ioat94k.h>
    #elif defined (__AVR_AT43USB320__)
    #  include <avr/io43u32x.h>
    #elif defined (__AVR_AT43USB355__)
    #  include <avr/io43u35x.h>
    #elif defined (__AVR_AT76C711__)
    #  include <avr/io76c711.h>
    #elif defined (__AVR_AT86RF401__)
    #  include <avr/io86r401.h>
    #elif defined (__AVR_AT90PWM1__)
    #  include <avr/io90pwm1.h>
    ...
    

    It's basically 500 lines of checking for which controller we are using. If you go to this file and with ctrl+f or something like that you can easily find how your controller is defined there and include it. This solves the problem because the DDRB and PORTB are now defined thanks to resolved pre-processor statements.