Arduino.h and wiring_digital.c problem.

Hi cmaglie.

Yes, it has been tested that way also, in fact, that is the original code.

stimmer:

P_LED = portOutputRegister(digitalPinToPort(13));

This line reads the current value of the port output register and stores it in P_LED. This is almost certainly not what you wanted to do.

Stimmer, I think I understand what you mean.

What we are trying to do is to get the port address.

This code in mega works this way:

#define sbi(reg, mask) *reg |= mask
#define cbi(reg, mask) *reg &= ~mask

volatile uint8_t * P_LED;
uint16_t B_LED;

void(loop)
{
P_LED = portOutputRegister(digitalPinToPort(13));
B_LED = digitalPinToBitMask(13);
sbi(P_LED,B_LED);
cbi(P_LED,B_LED);
}

But when we ported this code to Due like this:

#define sbi(reg, mask) *reg |= mask
#define cbi(reg, mask) *reg &= ~mask

volatile uint32_t * P_LED;
uint32_t B_LED;

void(loop)
{
P_LED = portOutputRegister(digitalPinToPort(13));
B_LED = digitalPinToBitMask(13);
sbi(P_LED,B_LED);
cbi(P_LED,B_LED);
}

It doens't compile complaining that RwREG is not compatible with volatile uint32_t*.

Can you give us a clue why?

I confess, i'm very bad with pointers...

alvesjc,

the portOutputRegister(..) currently is returning the actual value of the port register instead of its address.

may you try this:

P_LED = &portOutputRegister(digitalPinToPort(13));

using the & to obtain the address of portOutputRegister.

BTW the definition for RwReg is:

typedef volatile uint32_t RwReg;

Ok, I'll try that in evening.

Meanwhile I'll get some reading for better understanding of your suggestion.

Thank you.

Here all the definitions in CMSIS:

file hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/sam3x8e.h, line 47

typedef volatile const uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */
#else
typedef volatile       uint32_t RoReg; /**< Read only 32-bit register (volatile const unsigned int) */
#endif
typedef volatile       uint32_t WoReg; /**< Write only 32-bit register (volatile unsigned int) */
typedef volatile       uint32_t RwReg; /**< Read-Write 32-bit register (volatile unsigned int) */

file hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/component/component_pio.h, line 40

/** \brief Pio hardware registers */
typedef struct {
  WoReg PIO_PER;       /**< \brief (Pio Offset: 0x0000) PIO Enable Register */
  WoReg PIO_PDR;       /**< \brief (Pio Offset: 0x0004) PIO Disable Register */
  RoReg PIO_PSR;       /**< \brief (Pio Offset: 0x0008) PIO Status Register */
  RoReg Reserved1[1];
  WoReg PIO_OER;       /**< \brief (Pio Offset: 0x0010) Output Enable Register */
  WoReg PIO_ODR;       /**< \brief (Pio Offset: 0x0014) Output Disable Register */
  RoReg PIO_OSR;       /**< \brief (Pio Offset: 0x0018) Output Status Register */
  RoReg Reserved2[1];
  WoReg PIO_IFER;      /**< \brief (Pio Offset: 0x0020) Glitch Input Filter Enable Register */
  WoReg PIO_IFDR;      /**< \brief (Pio Offset: 0x0024) Glitch Input Filter Disable Register */
  RoReg PIO_IFSR;      /**< \brief (Pio Offset: 0x0028) Glitch Input Filter Status Register */
  RoReg Reserved3[1];
  WoReg PIO_SODR;      /**< \brief (Pio Offset: 0x0030) Set Output Data Register */
  WoReg PIO_CODR;      /**< \brief (Pio Offset: 0x0034) Clear Output Data Register */
  RwReg PIO_ODSR;      /**< \brief (Pio Offset: 0x0038) Output Data Status Register */
  RoReg PIO_PDSR;      /**< \brief (Pio Offset: 0x003C) Pin Data Status Register */
  WoReg PIO_IER;       /**< \brief (Pio Offset: 0x0040) Interrupt Enable Register */
  WoReg PIO_IDR;       /**< \brief (Pio Offset: 0x0044) Interrupt Disable Register */
  RoReg PIO_IMR;       /**< \brief (Pio Offset: 0x0048) Interrupt Mask Register */
  RoReg PIO_ISR;       /**< \brief (Pio Offset: 0x004C) Interrupt Status Register */
  WoReg PIO_MDER;      /**< \brief (Pio Offset: 0x0050) Multi-driver Enable Register */
  WoReg PIO_MDDR;      /**< \brief (Pio Offset: 0x0054) Multi-driver Disable Register */
  RoReg PIO_MDSR;      /**< \brief (Pio Offset: 0x0058) Multi-driver Status Register */
  RoReg Reserved4[1];
  WoReg PIO_PUDR;      /**< \brief (Pio Offset: 0x0060) Pull-up Disable Register */
  WoReg PIO_PUER;      /**< \brief (Pio Offset: 0x0064) Pull-up Enable Register */
  RoReg PIO_PUSR;      /**< \brief (Pio Offset: 0x0068) Pad Pull-up Status Register */
  RoReg Reserved5[1];
  RwReg PIO_ABSR;      /**< \brief (Pio Offset: 0x0070) Peripheral AB Select Register */
  RoReg Reserved6[3];
  WoReg PIO_SCIFSR;    /**< \brief (Pio Offset: 0x0080) System Clock Glitch Input Filter Select Register */
  WoReg PIO_DIFSR;     /**< \brief (Pio Offset: 0x0084) Debouncing Input Filter Select Register */
  RoReg PIO_IFDGSR;    /**< \brief (Pio Offset: 0x0088) Glitch or Debouncing Input Filter Clock Selection Status Register */
  RwReg PIO_SCDR;      /**< \brief (Pio Offset: 0x008C) Slow Clock Divider Debouncing Register */
  RoReg Reserved7[4];
  WoReg PIO_OWER;      /**< \brief (Pio Offset: 0x00A0) Output Write Enable */
  WoReg PIO_OWDR;      /**< \brief (Pio Offset: 0x00A4) Output Write Disable */
  RoReg PIO_OWSR;      /**< \brief (Pio Offset: 0x00A8) Output Write Status Register */
  RoReg Reserved8[1];
  WoReg PIO_AIMER;     /**< \brief (Pio Offset: 0x00B0) Additional Interrupt Modes Enable Register */
  WoReg PIO_AIMDR;     /**< \brief (Pio Offset: 0x00B4) Additional Interrupt Modes Disables Register */
  RoReg PIO_AIMMR;     /**< \brief (Pio Offset: 0x00B8) Additional Interrupt Modes Mask Register */
  RoReg Reserved9[1];
  WoReg PIO_ESR;       /**< \brief (Pio Offset: 0x00C0) Edge Select Register */
  WoReg PIO_LSR;       /**< \brief (Pio Offset: 0x00C4) Level Select Register */
  RoReg PIO_ELSR;      /**< \brief (Pio Offset: 0x00C8) Edge/Level Status Register */
  RoReg Reserved10[1];
  WoReg PIO_FELLSR;    /**< \brief (Pio Offset: 0x00D0) Falling Edge/Low Level Select Register */
  WoReg PIO_REHLSR;    /**< \brief (Pio Offset: 0x00D4) Rising Edge/ High Level Select Register */
  RoReg PIO_FRLHSR;    /**< \brief (Pio Offset: 0x00D8) Fall/Rise - Low/High Status Register */
  RoReg Reserved11[1];
  RoReg PIO_LOCKSR;    /**< \brief (Pio Offset: 0x00E0) Lock Status */
  RwReg PIO_WPMR;      /**< \brief (Pio Offset: 0x00E4) Write Protect Mode Register */
  RoReg PIO_WPSR;      /**< \brief (Pio Offset: 0x00E8) Write Protect Status Register */
} Pio;

file hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3xa/include/sam3x8e.h, line 494

#define PIOA       ((Pio    *)0x400E0E00U) /**< \brief (PIOA      ) Base Address */
#define PIOB       ((Pio    *)0x400E1000U) /**< \brief (PIOB      ) Base Address */
#define PIOC       ((Pio    *)0x400E1200U) /**< \brief (PIOC      ) Base Address */
#define PIOD       ((Pio    *)0x400E1400U) /**< \brief (PIOD      ) Base Address */

PIOA, for example, is a pointer to a Pio structure located exactly over the memory mapped registers, this way we can access, say, ODSR using PIOA->PIO_ODSR (access to a structure member located exactly over the register), and its what the macro portOutputRegister actually does.

Said that, the original meaning of the macro portOutputRegister(..) was to give the address of that register, so the define in Arduino.h is wrong and it should be changed from:

(...aehm..edited...)

#define portOutputRegister(port)   ( port->PIO_ODSR )
#define portInputRegister(port)    ( port->PIO_PDSR )

to:

#define portOutputRegister(port)   ( &(port->PIO_ODSR) )
#define portInputRegister(port)    ( &(port->PIO_PDSR) )

I'm waiting the results of your test! :slight_smile:

Ok ok ok, if I get it right, that means that I'll not need to add the ampersand to "portOutputRegister(digitalPinToPort(13))" as your previous suggestion, because "( &(port->PIO_PDSR) )" will already return that pointer, right?

By the way, can you explain me the meaning of "->"? Or point me to some place to read about it?

I'm not finding any reference to it.

Thank you.

BR,

Joao

alvesjc:
Ok ok ok, if I get it right, that means that I'll not need to add the ampersand to "portOutputRegister(digitalPinToPort(13))" as your previous suggestion, because "( &(port->PIO_PDSR) )" will already return that pointer, right?

exactly.

alvesjc:
By the way, can you explain me the meaning of "->"? Or point me to some place to read about it?

when you have a pointer to a structure the "->" operator is used to access a member of the pointed structure. Without this operator you should write something like:

(*PIOA).PIO_PDSR

whete *PIOA is the structure instance pointed by PIOA and .PIO_PDSR is the member selector. You need also the parenthesis because . has higher priority versus *. Since this kind of access is used very often, the C language defines the -> operator so you can write a more concise:

PIOA->PIO_PDSR

if you need more info a google search for "pointer to structure" will give you a lot of articles.

Thanks again cmaglie, your fix on the Arduino.h puts everything working on the right spot. :slight_smile:
I hope it will sent to GIT so the last version comes out fixed with that.

Now all code works like a charme, I wonder now if we still can not optimize it a bit more since we are still using on the ports writing routines the REG_PIOD_SODR register, do you think this can also be changed for ODSR?

The problem with ODSR is when you write something there what was before gets cleared, so I think I need to do the proper logic just to change what´s new and maintain what was previous, no?

cmaglie:

alvesjc:
Ok ok ok, if I get it right, that means that I'll not need to add the ampersand to "portOutputRegister(digitalPinToPort(13))" as your previous suggestion, because "( &(port->PIO_PDSR) )" will already return that pointer, right?

exactly.

alvesjc:
By the way, can you explain me the meaning of "->"? Or point me to some place to read about it?

when you have a pointer to a structure the "->" operator is used to access a member of the pointed structure. Without this operator you should write something like:

(*PIOA).PIO_PDSR

whete *PIOA is the structure instance pointed by PIOA and .PIO_PDSR is the member selector. You need also the parenthesis because . has higher priority versus *. Since this kind of access is used very often, the C language defines the -> operator so you can write a more concise:

PIOA->PIO_PDSR

if you need more info a google search for "pointer to structure" will give you a lot of articles.

Ok, thank you for your time explaining. :wink:

BR,

Joao

cmaglie:
I'm waiting the results of your test! :slight_smile:

Ok, working fine now, thanks for your help!

With direct port communication with SODR and CODR for data pins we have gained +-13s in UTFT Demo code loop, a HUGE difference!!!

Regards,

Joao

Hello alvesjc

Can you put the sample code you already it works.
I refer to the set of sbi, cbi.

It would be far better that you put the modified UTFT to download.

I have cast a write methods for UTFT ports that I have not been able to apply, but I set the display directly and go very fast, I would like to adapt the library and send it to the developer to UTFT but I'm missing that part.

Thanks

After doing some tests, I see that it works by putting the code which says cmaglie.

REG_PIOA_OWER = 0xFFFFFFFF;
REG_PIOB_OWER = 0xFFFFFFFF;
REG_PIOC_OWER = 0xFFFFFFFF;

then hit the code.

#define sbi(reg, mask) *reg |= mask
#define cbi(reg, mask) *reg &= ~mask

int led = 13;
volatile uint32_t * Registro;
uint32_t Mascara;

// the setup routine runs once when you press reset:
void setup() {                
  REG_PIOA_OWER = 0xFFFFFFFF;
  REG_PIOB_OWER = 0xFFFFFFFF;
  REG_PIOC_OWER = 0xFFFFFFFF;
  Registro	= portOutputRegister(digitalPinToPort(led));
  Mascara	= digitalPinToBitMask(led);
  // initialize the digital pin as an output.
  pinMode(led, OUTPUT);    
  
  
}

// the loop routine runs over and over again forever:
void loop() {
  sbi(Registro,Mascara);
  delay(1000);               // wait for a second
  cbi(Registro,Mascara);
  delay(1000);               // wait for a second
}

Hi Amolinero.

The latest IDE version fixes the problems with SBI and CBI Macros. You don't need to set OWER registers anymore.

I've also modified the communication with ports to work with due at a very reasonable speed.

I run now the DEMO code from Henning in 32s now.

I've modified UTFT::LCD_Writ_Bus function switch this way:

	case 16:

                //Clear port registers
                REG_PIOA_CODR=0xc080; //PA7,PA14,PA15
                REG_PIOB_CODR=0x4000000; //PB26
                REG_PIOC_CODR=0x3e; //PC1 - PC5
                REG_PIOD_CODR=0x64f; //PD0-3,PD6,PD9-10
                
		//DB00 on PIN37 -> PIO_PC5
                REG_PIOC_SODR=(VL<<5) & 0x20;
                //DB01 on PIN36 -> PIO_PC4
                REG_PIOC_SODR=(VL<<3) & 0x10;
                //DB02 on PIN35 -> PIO_PC3
                REG_PIOC_SODR=(VL<<1) & 0x08;
                //DB03 on PIN34 -> PIO_PC2
                REG_PIOC_SODR=(VL>>1) & 0x04;
                //DB04 on PIN33 -> PIO_PC1
                REG_PIOC_SODR=(VL>>3) & 0x02;
                //DB05 on PIN32 -> PIO_PD10
                REG_PIOD_SODR=(VL<<5) & 0x400;
                //DB06 on PIN31 -> PIO_PA7
                REG_PIOA_SODR=(VL<<1) & 0x80;
                //DB07 on PIN30 -> PIO_PD9
                REG_PIOD_SODR=(VL<<2) & 0x200;
                //DB08 on PIN22 -> PIO_PB26
                REG_PIOB_SODR=(VH<<26) & 0x4000000;
                //DB09 on PIN23 -> PIO_PA14
                REG_PIOA_SODR=(VH<<13) & 0x4000;
                //DB10 on PIN24 -> PIO_PA15
                REG_PIOA_SODR=(VH<<13) & 0x8000;
                //DB11 on PIN25 -> PIO_PD0
                REG_PIOD_SODR=(VH>>3) & 0x01;
                //DB12 on PIN26 -> PIO_PD1
                REG_PIOD_SODR=(VH>>3) & 0x02;
                //DB13 on PIN27 -> PIO_PD2
                REG_PIOD_SODR=(VH>>3) & 0x04;
                //DB14 on PIN28 -> PIO_PD3
                REG_PIOD_SODR=(VH>>3) & 0x08;
                //DB15 on PIN29 -> PIO_PD6
                REG_PIOD_SODR=(VH>>1) & 0x40;

#endif
                pulse_low(P_WR, B_WR);

                break;

And the UTFT::_set_direction_registers Function this way:

	if (mode==16)
	{
		
		REG_PIOA_OER=0xc080; //PA7,PA14,PA15 enable
		REG_PIOB_OER=0x4000000; //PB26 enable
		REG_PIOC_OER=0x3e; //PC1 - PC5 enable
		REG_PIOD_OER=0x64f; //PD0-3,PD6,PD9-10 enable
}

I've only cared with 16 bit part, my display is 16bit version.

Hope this helps.

Thank you very much for your answer

Can't get utft library to work even how hard I try. I just end up with empty white screen backlit..

I added cbi and sbi defines to beginning of UTFT.cpp and HW_AVR.h - removed all
other mode stuff than mode 16 from HW_AVR.h and changed regtype's type definition to volatile rwreg..

Also, I grabbed pgmspace.h from another thread and included it whenever AVR/pgmspace.h is requested.
Code compiles without problems. Shield is at 3.3v setting and mega pins is selected in demo 320x240.

Nothing happens. What am I doing wrong?
I have itdb32s and mega shield for it from
Iteadstudios..

alvesjc - what display you are having? (and how is connected, with shield? what shield? or by wires, how did you wire it?)

In the first define, change UTFT.c by this

#if defined(__AVR__)
	#include <avr/pgmspace.h>
	#include "HW_AVR.h" 
#elif defined(__SAM3X8E__)
	#include "Arduino.h"
	#include "HW_SAM.h" 
#else
	#include "HW_PIC32.h"
#endif

In the define AVR of file UTFT.h change by this

#if defined(__AVR__)
	#if defined(ARDUINO) && ARDUINO >= 100
		#include "Arduino.h"
	#else
		#include "WProgram.h"
	#endif
	#include "HW_AVR_defines.h"
#elif defined(__SAM3X8E__)
	#include "Arduino.h"
	#include "HW_SAM_defines.h"
#else
	#include "WProgram.h"
	#include "HW_PIC32_defines.h"
#endif

copy HW_AVR_defines.h to HW_SAM_defines.h
copy HW_AVR.h to HW_SAM.h
Changes HW_SAM_defines.h by this

#define cbi(reg, bitmask) *reg &= ~bitmask
#define sbi(reg, bitmask) *reg |= bitmask
#define pulse_high(reg, bitmask) sbi(reg, bitmask); cbi(reg, bitmask);
#define pulse_low(reg, bitmask) cbi(reg, bitmask); sbi(reg, bitmask);

#define pgm_read_word(data) *data
#define pgm_read_byte(data) *data

#define cport(port, data) port &= data
#define sport(port, data) port |= data

#define swap(type, i, j) {type t = i; i = j; j = t;}

#define fontbyte(x) cfont.font[x]  

#define regtype volatile uint32_t
#define regsize uint32_t
#define bitmapdatatype unsigned uint16_t

Changes HW_SAM.h by this

// *** Hardwarespecific functions ***
void UTFT::LCD_Writ_Bus(char VH,char VL, byte mode)
{   
	switch (mode)
	{
	case 1:
		if (display_serial_mode==SERIAL_4PIN)
		{
		if (VH==1)
			sbi(P_SDA, B_SDA);
		else
			cbi(P_SDA, B_SDA);
		pulse_low(P_SCL, B_SCL);
		}
		else
		{
		if (VH==1)
			sbi(P_RS, B_RS);
		else
			cbi(P_RS, B_RS);
		}

		if (VL & 0x80)
			sbi(P_SDA, B_SDA);
		else
			cbi(P_SDA, B_SDA);
		pulse_low(P_SCL, B_SCL);
		if (VL & 0x40)
			sbi(P_SDA, B_SDA);
		else
			cbi(P_SDA, B_SDA);
		pulse_low(P_SCL, B_SCL);
		if (VL & 0x20)
			sbi(P_SDA, B_SDA);
		else
			cbi(P_SDA, B_SDA);
		pulse_low(P_SCL, B_SCL);
		if (VL & 0x10)
			sbi(P_SDA, B_SDA);
		else
			cbi(P_SDA, B_SDA);
		pulse_low(P_SCL, B_SCL);
		if (VL & 0x08)
			sbi(P_SDA, B_SDA);
		else
			cbi(P_SDA, B_SDA);
		pulse_low(P_SCL, B_SCL);
		if (VL & 0x04)
			sbi(P_SDA, B_SDA);
		else
			cbi(P_SDA, B_SDA);
		pulse_low(P_SCL, B_SCL);
		if (VL & 0x02)
			sbi(P_SDA, B_SDA);
		else
			cbi(P_SDA, B_SDA);
		pulse_low(P_SCL, B_SCL);
		if (VL & 0x01)
			sbi(P_SDA, B_SDA);
		else
			cbi(P_SDA, B_SDA);
		pulse_low(P_SCL, B_SCL);
		break;
	case 8:
		// NOT IMPLEMENTED
		break;
	case 16:
		//Clear port registers
		REG_PIOA_CODR=0xc080; //PA7,PA14,PA15
		REG_PIOB_CODR=0x4000000; //PB26
		REG_PIOC_CODR=0x3e; //PC1 - PC5
		REG_PIOD_CODR=0x64f; //PD0-3,PD6,PD9-10
                
		//DB00 on PIN37 -> PIO_PC5
		REG_PIOC_SODR=(VL<<5) & 0x20;
		//DB01 on PIN36 -> PIO_PC4
		REG_PIOC_SODR=(VL<<3) & 0x10;
		//DB02 on PIN35 -> PIO_PC3
		REG_PIOC_SODR=(VL<<1) & 0x08;
		//DB03 on PIN34 -> PIO_PC2
		REG_PIOC_SODR=(VL>>1) & 0x04;
		//DB04 on PIN33 -> PIO_PC1
		REG_PIOC_SODR=(VL>>3) & 0x02;
		//DB05 on PIN32 -> PIO_PD10
		REG_PIOD_SODR=(VL<<5) & 0x400;
		//DB06 on PIN31 -> PIO_PA7
		REG_PIOA_SODR=(VL<<1) & 0x80;
		//DB07 on PIN30 -> PIO_PD9
		REG_PIOD_SODR=(VL<<2) & 0x200;
		//DB08 on PIN22 -> PIO_PB26
		REG_PIOB_SODR=(VH<<26) & 0x4000000;
		//DB09 on PIN23 -> PIO_PA14
		REG_PIOA_SODR=(VH<<13) & 0x4000;
		//DB10 on PIN24 -> PIO_PA15
		REG_PIOA_SODR=(VH<<13) & 0x8000;
		//DB11 on PIN25 -> PIO_PD0
		REG_PIOD_SODR=(VH>>3) & 0x01;
		//DB12 on PIN26 -> PIO_PD1
		REG_PIOD_SODR=(VH>>3) & 0x02;
		//DB13 on PIN27 -> PIO_PD2
		REG_PIOD_SODR=(VH>>3) & 0x04;
		//DB14 on PIN28 -> PIO_PD3
		REG_PIOD_SODR=(VH>>3) & 0x08;
		//DB15 on PIN29 -> PIO_PD6
		REG_PIOD_SODR=(VH>>1) & 0x40;

		pulse_low(P_WR, B_WR);
		break;
	}
}

void UTFT::_set_direction_registers(byte mode)
{
	if (mode==16)
	{
		REG_PIOA_OER=0xc080; //PA7,PA14,PA15 enable
		REG_PIOB_OER=0x4000000; //PB26 enable
		REG_PIOC_OER=0x3e; //PC1 - PC5 enable
		REG_PIOD_OER=0x64f; //PD0-3,PD6,PD9-10 enable
	}
}

If it works, let me know and I use it, I have not tried.

If winds are going to send him UTFT developer to implement it.

regards

Thanks to amolinero, I got it to work! Perfect.. Well, could be faster, but for the moment, this is great progress!

Hi!

Ok, glad you made it, sorry I was out.

Have you tested with UTFT_DEMO? What is your loop time?

Currently it takes 352 milliseconds to clean the screen.

It is an acceptable time.