digitalPinToPort macro failure

Has anyone seen this or have a suggested fix? Here’s the error report from the compiler.

error: invalid conversion from ‘PortGroup*’ to ‘uint8_t {aka unsigned char}’ [-fpermissive]

#define digitalPinToPort(P) (&(PORT->Group[g_APinDescription[P].ulPort]))

When I look at the definitions in all of the SAMD variants, they’re all the same, so anyone using a digitalPinToPort function should have the same problem. I’m not expert enough to know what to do here.

Please post your full sketch.

If possible, you should always post code directly in the forum thread as text using code tags:

  • Do an Auto Format (Tools > Auto Format in the Arduino IDE or Ctrl + B in the Arduino Web Editor) on your code. This will make it easier for you to spot bugs and make it easier for us to read.
  • In the Arduino IDE or Arduino Web Editor, click on the window that contains your sketch code.
  • Press “Ctrl + A”. This will select all the text.
  • Press “Ctrl + C”. This will copy the selected text to the clipboard.
  • In a forum reply here, click the “Reply” button.
  • click on the reply field.
  • Click the </> button on the forum toolbar. This will add the forum’s code tags markup to your reply.
  • Press “Ctrl + V”. This will paste the sketch between the code tags.
  • Move the cursor outside of the code tags before you add any additional text to your reply.
  • Repeat the above process if your sketch has multiple tabs.

This will make it easy for anyone to look at it, which will increase the likelihood of you getting help.

If the sketch is longer than the 9000 characters maximum allowed by the forum, then it’s OK to add it as an attachment. After clicking the “Reply” button, you will see an “Attachments and other settings” link.

When your code requires a library that’s not included with the Arduino IDE please post a link (using the chain links icon on the forum toolbar to make it clickable) to where you downloaded that library from or if you installed it using Library Manger (Sketch > Include Library > Manage Libraries in the Arduino IDE or Libraries > Library Manager in the Arduino Web Editor) then say so and state the full name of the library.

I am trying to run a sensor library on the Nano_33_IOT and I get this error

error: invalid conversion from 'PortGroup*' to 'uint8_t {aka unsigned char}' [-fpermissive]

define digitalPinToPort(P) (&(PORT->Group[g_APinDescription[P].ulPort]))

in this context

DHT_nonblocking::DHT_nonblocking( uint8_t pin, uint8_t type ) : _pin( pin ), _type( type ), _bit( digitalPinToBitMask( pin ) ), _port( digitalPinToPort( pin ) ), _maxcycles( microsecondsToClockCycles( 1000 ) ) { dht_state = DHT_IDLE;

pinMode( _pin, INPUT ); digitalWrite( _pin, HIGH ); }

The macro is defined in Arduino15\packages\arduino\hardware\samd\1.8.5\variants\nano_33_iot/variant.h

I looked at the other SAMD variants and they all have the same macro definition. So is it a problem in variant.h? or in the usage function.

Any suggestions on how to fix it?

Thanks,

David

Here’s the sketch. No problem with it.
//2018.6.28
#include <dht_nonblocking.h>

#define DHT_SENSOR_TYPE DHT_TYPE_11
//#define DHT_SENSOR_TYPE DHT_TYPE_21
//#define DHT_SENSOR_TYPE DHT_TYPE_22

static const int DHT_SENSOR_PIN = 11;
DHT_nonblocking dht_sensor( DHT_SENSOR_PIN, DHT_SENSOR_TYPE );

void setup( )
{
Serial.begin( 9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
}
void loop( )
{
float temperature;
float humidity;

if(dht_sensor.measure(&temperature, &humidity)){
Serial.print( "T = " );
Serial.print( temperature, 1 );
Serial.print( " deg. C, H = " );
Serial.print( humidity, 1 );
Serial.println( “%” );
}
}

Here’s the DHT library

/*

  • DHT11, DHT21, and DHT22 non-blocking library.
  • Based on Adafruit Industries’ DHT driver library.
  • (C) 2015 Ole Wolf wolf@blazingangles.com
  • This program 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.
  • This program 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 this program. If not, see http://www.gnu.org/licenses/.
    */

#include “dht_nonblocking.h”

#define DHT_IDLE 0
#define DHT_BEGIN_MEASUREMENT 1
#define DHT_BEGIN_MEASUREMENT_2 2
#define DHT_DO_READING 3
#define DHT_COOLDOWN 4

/* Number of milliseconds before a new sensor read may be initiated. */
#define COOLDOWN_TIME 2000

/*

  • Constructor for the sensor. It remembers the pin number and the
  • type of sensor, and initializes internal variables.
    */
    DHT_nonblocking::DHT_nonblocking( uint8_t pin, uint8_t type )
    : _pin( pin ),
    _type( type ),
    _bit( digitalPinToBitMask( pin ) ),
    _port( digitalPinToPort( pin ) ),
    _maxcycles( microsecondsToClockCycles( 1000 ) )
    {
    dht_state = DHT_IDLE;

pinMode( _pin, INPUT );
digitalWrite( _pin, HIGH );
}

/*

  • Instruct the DHT to begin sampling. Keep polling until it returns true.
  • The tempearture is in degrees Celsius, and the humidity is in %.
    */
    bool DHT_nonblocking::measure( float *temperature, float *humidity )
    {
    if( read_nonblocking( ) == true )
    {
    *temperature = read_temperature( );
    *humidity = read_humidity( );
    return( true );
    }
    else
    {
    return( false );
    }
    }

float DHT_nonblocking::read_temperature( ) const
{
int16_t value;
float to_return;

switch( _type )
{
case DHT_TYPE_11:
value = data[ 2 ];
to_return = (float) value;
break;

case DHT_TYPE_21:
case DHT_TYPE_22:
value = ( data[ 2 ] & 0x7f ) << 8;
value |= data[ 3 ];
if( ( data[ 2 ] & 0x80 ) != 0 )
{
value = -value;
}
to_return = ( (float) value ) / 10.0;
break;

default:
to_return = NAN;
break;
}

return( to_return );
}

float DHT_nonblocking::read_humidity( ) const
{
uint16_t value;
float to_return;

switch( _type )
{
case DHT_TYPE_11:
value = data[ 0 ];
to_return = (float) value;
break;

case DHT_TYPE_21:
case DHT_TYPE_22:
value = data[ 0 ] << 8;
value |= data[ 1 ];
to_return = (float)value / 10.0;
break;

default:
to_return = NAN;
break;
}

return( to_return );
}

/*

  • Expect the input to be at the specified level and return the number
  • of loop cycles spent there. This is identical to Adafruit’s blocking
  • driver.
    */
    uint32_t DHT_nonblocking::expect_pulse(bool level) const
    {
    uint32_t count = 0;
    // On AVR platforms use direct GPIO port access as it’s much faster and better
    // for catching pulses that are 10’s of microseconds in length:
    #ifdef __AVR
    uint8_t portState = level ? _bit : 0;
    while ((*portInputRegister(_port) & _bit) == portState) {
    if (count++ >= _maxcycles) {
    return 0; // Exceeded timeout, fail.
    }
    }
    // Otherwise fall back to using digitalRead (this seems to be necessary on ESP8266
    // right now, perhaps bugs in direct port access functions?).
    #else
    while (digitalRead(_pin) == level) {
    if (count++ >= _maxcycles) {
    return 0; // Exceeded timeout, fail.
    }
    }
    #endif

return count;
}

/*

  • State machine of the non-blocking read.
    */
    bool DHT_nonblocking::read_nonblocking( )
    {
    bool status = false;

switch( dht_state )
{
/* We may begin measuring any time. */
case DHT_IDLE:
dht_state = DHT_BEGIN_MEASUREMENT;
break;

/* Initiate a sensor read. The read begins by going to high impedance
state for 250 ms. /
case DHT_BEGIN_MEASUREMENT:
digitalWrite( _pin, HIGH );
/
Reset 40 bits of received data to zero. */
data[ 0 ] = data[ 1 ] = data[ 2 ] = data[ 3 ] = data[ 4 ] = 0;
dht_timestamp = millis( );
dht_state = DHT_BEGIN_MEASUREMENT_2;
break;

/* After the high impedance state, pull the pin low for 20 ms. /
case DHT_BEGIN_MEASUREMENT_2:
/
Wait for 250 ms. */
if( millis( ) - dht_timestamp > 250 )
{
pinMode( _pin, OUTPUT );
digitalWrite( _pin, LOW );
dht_timestamp = millis( );
dht_state = DHT_DO_READING;
}
break;

case DHT_DO_READING:
/* Wait for 20 ms. */
if( millis( ) - dht_timestamp > 20 )
{
dht_timestamp = millis( );
dht_state = DHT_COOLDOWN;
status = read_data( );
// if( status != true )
// {
// Serial.println( “Reading failed” );
// }
}
break;

/* If it has been less than two seconds since the last time we read
the sensor, then let the sensor cool down… */
case DHT_COOLDOWN:
if( millis( ) - dht_timestamp > COOLDOWN_TIME )
{
dht_state = DHT_IDLE;
}
break;

default:
break;
}

return( status );
}

/* Read sensor data. This is identical to Adafruit’s blocking driver. */
bool DHT_nonblocking::read_data( )
{
uint32_t cycles[ 80 ];

/* Turn off interrupts temporarily because the next sections are timing critical
and we don’t want any interruptions. */
{
volatile DHT_interrupt interrupt;

// End the start signal by setting data line high for 40 microseconds.
digitalWrite( _pin, HIGH );
delayMicroseconds( 40 );

// Now start reading the data line to get the value from the DHT sensor.
pinMode( _pin, INPUT );
// Delay a bit to let sensor pull data line low.
delayMicroseconds( 10 );

// First expect a low signal for ~80 microseconds followed by a high signal
// for ~80 microseconds again.
if( expect_pulse( LOW ) == 0 )
{
return( false );
}
if( expect_pulse( HIGH ) == 0 )
{
return( false );
}

// Now read the 40 bits sent by the sensor. Each bit is sent as a 50
// microsecond low pulse followed by a variable length high pulse. If the
// high pulse is ~28 microseconds then it’s a 0 and if it’s ~70 microseconds
// then it’s a 1. We measure the cycle count of the initial 50us low pulse
// and use that to compare to the cycle count of the high pulse to determine
// if the bit is a 0 (high state cycle count < low state cycle count), or a
// 1 (high state cycle count > low state cycle count). Note that for speed all
// the pulses are read into a array and then examined in a later step.
for( int i = 0; i < 80; i += 2 )
{
cycles[ i ] = expect_pulse( LOW );
cycles[ i + 1 ] = expect_pulse( HIGH );
}

/* Timing critical code is now complete. */
}

// Inspect pulses and determine which ones are 0 (high state cycle count < low
// state cycle count), or 1 (high state cycle count > low state cycle count).
for( int i = 0; i < 40; ++i )
{
uint32_t low_cycles = cycles[ 2 * i ];
uint32_t high_cycles = cycles[ 2 * i + 1 ];
if( ( low_cycles == 0 ) || ( high_cycles == 0 ) )
{
return( false );
}
data[ i / 8 ] <<= 1;
// Now compare the low and high cycle times to see if the bit is a 0 or 1.
if( high_cycles > low_cycles )
{
// High cycles are greater than 50us low cycle count, must be a 1.
data[ i / 8 ] |= 1;
}
// Else high cycles are less than (or equal to, a weird case) the 50us low
// cycle count so this must be a zero. Nothing needs to be changed in the
// stored data.
}

// Check we read 40 bits and that the checksum matches.
if( data[ 4 ] == ( ( data[ 0 ] + data[ 1 ] + data[ 2 ] + data[ 3 ]) & 0xFF ) )
{
return( true );
}
else
{
return( false );
}
}

So is it a problem in variant.h? or in the usage function.

In the usage. digitalPinToPort() is s standard part of the Arduino core, used by things like "pinMode()" and "digitalWrite()"

You try to initialize a byte by a pointer to a PortGroup.

Obviously you need a different data type to represent a port in the new Nanos.

The first step would be to change the '_port' member variable in the DHT object from 'byte'/'uint8_t' to 'PortGroup *'. It might be prudent to change the name to something like '_portGroup' so the compiler will throw an error everywhere that '_port' is used. You'll then have to change those parts of the library to use the new syntax.

You may want to use preprocessor conditionals so that the library can be used on the old platforms as well as the new.

I have two sensor libraries that depend on macros that are defined in the Nano_33_IOT variant file that the compiler doesn’t like. But when I compile for the UNO, they work. They macros are in the area of assigning pins to ports. Here are a couple of examples, and I’ve attached the offending libraries and the variant file for the Nano_33_IOT. The definitions in other SAMB variants are the same for these macros. The question is how to fix the problem

  1. From a sensor library called dht_nonblocking
    In constructor ‘DHT_nonblocking::DHT_nonblocking(uint8_t, uint8_t)’:

C:\Users\David Duehren\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.8.5\variants\nano_33_iot/variant.h:50:35: error: invalid conversion from ‘PortGroup*’ to ‘uint8_t {aka unsigned char}’ [-fpermissive]

#define digitalPinToPort(P) (&(PORT->Group[g_APinDescription[P].ulPort]))

~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

D:\David\MyDocuments\Arduino\libraries\DHT\dht_nonblocking.cpp:44:11: note: in expansion of macro ‘digitalPinToPort’

_port( digitalPinToPort( pin ) ),

  1. From another sensor library called NewPing
    In constructor ‘NewPing::NewPing(uint8_t, uint8_t, int)’:

C:\Users\David Duehren\AppData\Local\Arduino15\packages\arduino\hardware\samd\1.8.5\variants\nano_33_iot/variant.h:53:51: error: cannot convert ‘volatile uint32_t* {aka volatile long unsigned int*}’ to ‘volatile uint8_t* {aka volatile unsigned char*}’ in assignment

#define portOutputRegister(port) (&(port->OUT.reg))

^

D:\David\MyDocuments\Arduino\libraries\NewPing\NewPing.cpp:19:19: note: in expansion of macro ‘portOutputRegister’

_triggerOutput = portOutputRegister(digitalPinToPort(trigger_pin)); // Get the output port register for the trigger pin.

NewPing.cpp (10.2 KB)

dht_nonblocking.cpp (7.9 KB)

variant.cpp (18.7 KB)

I’ve merged your cross-posts @dduehren.

Cross-posting is against the rules of the forum. The reason is that duplicate posts can waste the time of the people trying to help. Someone might spend 15 minutes (or more) writing a detailed answer on this topic, without knowing that someone else already did the same in the other topic.

Repeated cross-posting will result in a suspension from the forum.

In the future, please take some time to pick the forum board that best suits the topic of your question and then only post once to that forum board. This is basic forum etiquette, as explained in the sticky “How to use this forum - please read.” post you will find at the top of every forum board. It contains a lot of other useful information. Please read it.

Thanks in advance for your cooperation.

dduehren: I have two sensor libraries that depend on macros that are defined in the Nano_33_IOT variant file that the compiler doesn't like. But when I compile for the UNO, they work.

Those libraries are hardware dependent and must be modified to be compatible with the Nano_33_IOT. You could learn how to modify them yourself (as I suggested above), or beg the library authors to modify their libraries to support a processor they don't have, or pay someone to modify the libraries for you (see the Gigs and Collaboration forum section).

Per your suggestion, I posted the relevant pieces of code in Gigs and Collaborators. https://forum.arduino.cc/index.php?topic=668329.0

I think if I can get one of these working, I can do the rest from that example. But was unable to follow your suggestion. I tried several things, the last of which was:

define REGTYPE uint32_t

class DHT_nonblocking { public: DHT_nonblocking( uint8_t pin, uint8_t type ); bool measure( float *temperature, float *humidity );

private: bool read_data( ); bool read_nonblocking( ); float read_temperature( ) const; float read_humidity( ) const;

uint8_t dht_state; unsigned long dht_timestamp; uint8_t data[ 6 ]; const uint8_t _pin, _type, _bit; const uint32_t _maxcycles; volatile REGTYPE *_port; // for the UNO _port was defined as uint8_t. I've also tried it // as volatile REGTYPE _port; // obviously I'm not much of a programmer.

uint32_t expect_pulse( bool level ) const; };

I got this to compile. I won't know if it works until later in the week when I get the 3.3V to 5.5V transceivers. Please review.

if defined(SAMD21G18A)

define REGTYPE PortGroup*

else

define REGTYPE uint8_t //UNO & other AVR processors, use 8 bit registers

endif

class DHT_nonblocking { public: DHT_nonblocking( uint8_t pin, uint8_t type ); bool measure( float *temperature, float *humidity );

private: bool read_data( ); bool read_nonblocking( ); float read_temperature( ) const; float read_humidity( ) const;

uint8_t dht_state; unsigned long dht_timestamp; uint8_t data[ 6 ]; const uint8_t _pin, _type, _bit; const uint32_t _maxcycles; REGTYPE _port;

uint32_t expect_pulse( bool level ) const; };