I wonder whether anyone else has noticed this issue with the Renesas RA4M1 GPIO switching? In my code, the GPIO is held high with INPUT_PULLUP when in idle state. When I need to send something, the GPIO is switched to OUTPUT HIGH. To send a bit the line is pulled LOW. On the Classic Nano this looks like a series of clean down/up pulses as expected. However, on the Renesas, the same trace shows artefacts. The best way I can explain is to illustrate this is using the two images attached. The artefacts can be seen on the right side of the second image.
Why would the GPIO briefly blip LOW when its being instructed by digitalWrite() to stay HIGH? Its like the instruction briefly causes the GPIO to turn off before switching it high again. This does appear to be causing some problems when high speed switching. I am using the same code on both the Classic and Renessas Nano boards and it uses the standard pinMode() and digitalWrite() functions, nothing fancy, although I have also observed the same behaviour when using the digitalWriteFast() function on the Renesas board.
The code is huge but i will try and come up with a small test case version needed.
Just wondering initially whether this is a known issue and also whether it can be mitigated using direct register writes somehow? I have played around with that for a while and managed to clean it up, but I suspect only because I wasn't able to get the code that switched the pull-ups on and off using direct register manipulation to work. If I use pinMode() instead, I get those artefacts.
It might be possible to read the pin configuration and see if it had been set to INPUT_PULLUP beforehand and set the output state accordingly. I didn't dig that deeply into it.
On the AVR, the pullup status is separate from the pin output status, so changing the pin direction doesn't change the pin value.
On the Renesas, the pullup status and pin state are both in the same register, so you have to "choose" which state the output bit will be in after changing mode. Letting it go to zero is the lazy way...
Thank you. I can probably modify that a little for my needs as I don't use the Hi-Z states. Its always either in input_pullup or output.
You do indeed have a point! Having checked the code, its doing pinMode() and then digitalWrite() for every byte instead of only at the beginning and end of the transmission.
I changed the code so that is sets all 8 GPIOs only at the beginning and end of the transmission. I now have a single blip on each of the data bus 8 GPIOs at the beginning of the transmission and at the end of the transmission rather than on each byte, which is an improvement. I think that the same problem might be affecting the control signals and impeding proper operation so I need to investigate this further and also test the hack provided by @van_der_decken .
At least I understand what is happening now. Thank you.
AFAIKT, pullup (PCR) and direction (PDR) bits are on the pin PFS register, while the PDR and output bit can be set on the port register. I am not sure why PDR is accessible on both registers. Given what you say above, it sounds like there is bound to be a short interval between setting pullup and subsequently the state of the output during which the GPIO will "idle". If there is a trick to keep it high (presumably this is what the code by @van_der_decken does - I have yet to test), then that would be cool.
This does do the job of pinMode() but I got exactly the same result as when using the existing standard Arduino version. Sorry but it didn't fix the problem of the blip, but I understand that it is a "first hack" and I appreciate the contribution. A curious conundrum this.
That's exactly what my code was doing. pinMode(pin, OUTPUT) then digitalWrite(pin, state) for several repetitions. Transitions from high to low and then back again to high are fine, but transitions high to high have the low blips in between. So yes, it does behave unexpectedly.
Oh, it fixes the problem of pinMode not setting the output HIGH when going from pinMode(pin, INPUT_PULLUP); to pinMode(pin, OUTPUT);. That works just fine. No glitches.
What doesn't work is if the pin has already been set to OUTPUT and is then set to OUTPUT a second time. In that case the pullup was turned off after the first call, PCR is LOW the next time it's checked and so the pin gets set LOW. There's your glitch.
It's a can of worms. And you know the old expression about the only way to close a can of worms after you've opened it is to use a bigger can.
Second approximation: you'd have to check on the prior input/output state (R_PORTx->PDR), check the PCR bit if you're going from input to output, or the R_PORTx->PODR bit if you were already in the output state.
What this will do in the case of a pin that was previously configured for an alternate function... is someone else's problem to solve. I've run out of bigger cans.
The code could OR the new pullup status into the PFS register instead of just writing it. Most of the PFS register is read/write.
Unfortunately, the Renesas libraries (which lie underneath the arduino code, do not seem to provide an API for reading that register, nor for writing to it non-destructively.
Funnily enough, I tried something like this earlier:
// Unlock PFS registers
R_PMISC->PWPR &= ~0x80; // Clear PWPR_B0WI to disable register write protection.
R_PMISC->PWPR |= 0x40; // Set PWPR_PFSWE to enable PFS register write access.
R_PFS->PORT[port_pin].PIN[pin].PmnPFS |= pcrbit; // Enable pull-up
R_PFS->PORT[port_pin].PIN[pin].PmnPFS &= ~pdrbit; // Set to input
// Re-lock PFS registers
R_PMISC->PWPR &= ~0x40; // Clear PWPR_PFSWE to disable PFS register write access.
R_PMISC->PWPR |= 0x80; // Set PWPR_BOWI re-enable register write protection.
The original for code (not mine) for setting BOWI and PFSWE was actually different, something like this:
// Unlock PFS registers
R_PMISC->PWPR = 0; // Clear PWPR_B0WI to disable register write protection.
R_PMISC->PWPR = 0x40; // Set PWPR_PFSWE to enable PFS register write access.
R_PFS->PORT[port_pin].PIN[pin].PmnPFS |= pcrbit; // Enable pull-up
R_PFS->PORT[port_pin].PIN[pin].PmnPFS &= ~pdrbit; // Set to input
// Re-lock PFS registers
R_PMISC->PWPR = 0; // Clear PWPR_PFSWE to disable PFS register write access.
R_PMISC->PWPR = 0x80; // Set PWPR_BOWI re-enable register write protection.
I didn't understand why the registers were being just set to a fixed value instead of being or'ed and and'ed to manipulate the relevant bit, so I changed it. However, if this register is also not readable then that starts to makes sense, but is, as you call it a "destructive set" because it doesn't take into account the existing bit values, it just overwrites them. Of course, from what you say, if PmnPFS is also not actually readable, then I am guessing this will be doing and or/and with zero (result of the attempted and failed read) and overwriting the register with that result, which explains why it didn't work.
The compiler didn't throw any errors so I expect the syntax must still have been valid even though the code didn't do what I expected it to.
It is rather disappointing if you can't manipulate the individual bits.
Something in the startup code leaves it unlocked, which is generally good, IMO.
I've been experimenting with digitalWriteFast() strategies using the PFS register.
(which incidentally also would also fix the problem where digitalWrite() doesn't turn off PWM on a pin. Without a speed penalty!)
It's not the hardware that has "destructive" properties, it's the Renesas fsp library
(So Arduino would need to be willing to drop below that library to fix it.)
I don't see any immediate reason that that wouldn't have worked.
I tried this out and it does change the bits as can be determined from the output from the Serial.println() statements. These do show changes from 'enabled' to 'disabled' and back, but writing the bits didn't seem to change the actual state of the GPIOs?
The LA showed the GPIOs all going LOW and just staying there. I also tried adding this:
R_PFS->PORT[_port].PIN[_pin].PmnPFS_b.PODR = 1; // Set output HIGH
but it made no difference. Not sure what might be missing.
The new My_PinMode() code still works the same as with the standard one. I can see that you are checking the state of PCR before decided whether to update it.
Did wonder whether I could get a reference to the pin that way. Thank you for the example.
Ah, that is interesting to know. I am now using the version by @van_der_decken because I think it more clearly expresses the intention.
I have now have my program working with standard commands as well as "fast" commands, except that the later uses either the standard pinMode() or the second version of your My_pinMode(). Using standard Arduino commands, the transmission takes about a millisecond, while with the "fast" commands and either pinMode() or My_PinMode(), it takes around 600uS to do the same thing, which is quite a bit faster. So it seems there is something to be gained by using "fast" routines, but perhaps not near as much as when using direct register writes on a classic Nano or Uno.
I realised that the same kind of blips were happening to the control bus and had to make changes to the code so that the certain pins on the control bus were switched only when there was actually a need to change direction. So that principle of remembering the last state and switching only when needed was helpful here as well. Unfortunately, these blips on the control side were causing the instrument to misbehave and abort the transmission.
Anyway its interesting to note that different hardware may present different problems even with the same code.
Works just fine for me. Putting the code in loop() to turn the pullup on and off with a delay(1); between them shows a sharp rise to 5V on the scope when the pullup is turned on, and a slow decay to 0V when it's turned off. Adding a 100K pulldown gives a nice sharp fall. So it's working as intended. A logic analyzer may not have a high enough impedance to register the relatively high resistance of the internal pullup.
And that is really the last time I've delving into this can of worms.
Thank you for the information. I appreciate the time you have taken to post such detailed information. It has been really helpful.
Your PmnPFS manipulation code does work perfectly and flashes the LED when used as shown in a new sketch. It ought to work the same where I have added it to my code, but it for some reason it does not, so I am obviously doing something wrong somewhere and will have to figure that out. However, your input has allowed my to move a considerable way forward for which I am very grateful.
You are right that its a bit of a can of worms, but not quite as bad as the Teensy 4 I think....