/*
*
* RP2040_IO-PORTS_utilities.ino
*
* https://forum.arduino.cc/t/pi-pico-port-registers/1022778/36
*
*
*
* Author: tbillion aug 2022 post #38
* ... wrote a bunch of high level helper functions, really just for organization and readability.
* also based on the scarce google results on these things maybe this will help someone
* in the future, below is a bunch of examples i made, i tested about 75 percent,
* strictly here for information purposes ...
*
* ... you can read and write GPIO_IN & GPIO_OUT for your application.
*
*
* ... Addition - all SDK function available in arduino using earlphilhower pico library
*
*
* -----------------------------------------------------------------------------------------------------------------------
*
*
* https://arduino-pico.readthedocs.io/en/latest/analog.html
*
* Analog Outputs
* The RP2040 does not have any onboard DACs, so analog outputs are simulated
* using the standard method of using pulse width modulation (PWM) using
* the RP2040’s hardware PWM units.
* While up to 16 PWM channels can be generated, they are not independent
* and there are significant restrictions as to allowed pins in parallel.
* See the RP2040 datasheet for full details.
*
* Analog Output Restrictions
* The PWM generator source clock restricts the legal combinations
* of frequency and ranges. At a CPU frequency of 133MHz, the 16 bit
* maximum range decreases by 1 bit for every doubling of the default
* PWM frequency of 1 kHz. For example, at 1MHz only about 6 bits
* of range are possible. When you define an analogWriteFreq and
* analogWriteRange that can’t be fulfilled by the hardware, the frequency
* will be preserved but the accuracy (range) will be reduced automatically.
* Your code will still send in the range you specify, but the core itself
* will transparently map it into the allowable PWN range.
*
* void analogWriteFreq(uint32_t freq)
* Sets the master PWM frequency used (i.e. how often the PWM output cycles).
* From 100Hz to 1MHz are supported.
*
* void analogWriteRange(uint32_t range) and analogWriteResolution(int res)
* These calls set the maximum PWM value (i.e. writing this value will result
* in a PWM duty cycle of 100%)/ either explicitly (range) or as a power-of-two
* (res). A range of 16 to 65535 is supported.
*
* void analogWrite(pin_size_t pin, int val)
* Writes a PWM value to a specific pin. The PWM machine is enabled and set
* to the requested frequency and scale, and the output is generated.
* This will continue until a digitalWrite or other digital output is performed.
*
*
* --------------------------------------------------------------------------------------
*
* for HELP UNDERSTANDING I/O REGISTERS LOOK AT THE CODE in the following sketches:
* > 3-RP2040_GPIO_16_LED_registers.ino <
* > 3-RP2040_GPIO_8_LED_registers_3.ino <
*
* --------------------------------------------------------------------------------------
*
*
*/
// ======================================================================================
// start of functions prototypes declarations
//
void setOE(uint32_t);
uint8_t countMidNums(uint8_t, uint8_t);
uint32_t getAllPinDirections();
uint32_t makeBitMaskOutAll();
uint32_t makeBitMaskInAll();
uint32_t makeBitMaskRange(uint8_t pins[], uint8_t, bool);
uint32_t makeBitMaskRangeNonClobber(uint8_t pins[], uint8_t, bool);
uint32_t makePutMask(uint8_t vals[], uint8_t);
// port/pin registers operations:
void setAllDigital();
void setAllOutput();
void setAllInput();
void setRangeDigital(uint8_t pins[], uint8_t);
void setRangeOutput(uint8_t pins[], uint8_t);
void setRangeInput(uint8_t pins[], uint8_t);
void setPortRange(uint8_t, uint8_t, bool);
void setPortRangeNonClobber(uint8_t, uint8_t, bool);
uint32_t readAllPorts();
uint32_t readPortRange(uint8_t, uint8_t);
uint32_t readPort1(uint8_t pins[], uint8_t);
void writeAllPorts(uint32_t);
void writeAllPorts1(uint8_t pinValues[], uint8_t);
void writePortRange(uint8_t pins[], uint8_t, uint8_t pinValues[], uint8_t);
void writePortRange1(uint8_t, uint8_t, uint8_t pinValues[], uint8_t);
// utilities:
void diagnosePinDir();
uint32_t reverseBits(uint32_t);
// console print:
void printBinary8(uint8_t, bool, bool);
void printBinary32(uint32_t, bool, bool);
void checkBits(uint8_t, bool);
//
// end of functions prototypes declarations
// ======================================================================================
// --------------------------------------------------------------------------------------
void setOE(uint32_t bitMask) {
//
for (uint8_t i = 0; i <= 31; i++) {
//
if ( ((i < 23) || (i > 25)) && ((i < 29) || (i > 31)) ) { // <SYSTEM> pins
//
if (bitRead(bitMask, i)) {
gpio_set_input_enabled(i, false); // output
} else {
gpio_set_input_enabled(i, true); // input
} // if-else
//
} // if
} // for
//
} // setOE()
uint8_t countMidNums(uint8_t a, uint8_t b) {
//
uint8_t c;
//
for (uint8_t i = a; i < b; i++) c = i;
//
return (c);
//
} // countMidNums()
uint32_t getAllPinDirections() {
//
uint32_t powResult = 0;
//
for (uint8_t i = 31; i >= 0; i--) {
//
if ( ((i < 23) || (i > 25)) && ((i < 29) || (i > 31)) ) { // <SYSTEM> pins
//
if (gpio_get_dir (i)) {
//powResult += pow(2, i); // use this to set an individual bit
bitWrite(powResult, 31 - i, 1);
//
} // if
//
} // if
//
} // for
//
return (powResult);
//
} // getAllPinDirections()
uint32_t makeBitMaskOutAll() {
//
uint32_t powResult = 0;
//
for (uint8_t i = 0; i <= 31; i++) {
//
if ( ((i < 23) || (i > 25)) && ((i < 29) || (i > 31)) ) { // <SYSTEM> pins
powResult += pow(2, i); //use this to set an individual bit
} // if
//
} // for
//
return (powResult);
//
} // makeBitMaskOutAll()
uint32_t makeBitMaskInAll() {
//
uint32_t powResult = 0b00011100011111111111111111111111; // bit-mask
//
for (uint8_t i = 0; i <= 31; i++) {
//
if ( ((i < 23) || (i > 25)) && ((i < 29) || (i > 31)) ) { // <SYSTEM> pins
powResult -= pow(2, i); //use this to set an individual bit
} // if
//
} // for
//
return (powResult);
//
} // makeBitMaskInAll()
uint32_t makeBitMaskRange(uint8_t pins[], uint8_t pinCount, bool IO) {
//
uint8_t val = 0;
uint32_t powResult = 0;
//
for (uint8_t i = 0; i < pinCount; i++) {
//
val = pins[i];
//
if ( ((val < 23) || (val > 25)) && ((val < 29) || (val > 31)) ) { // <SYSTEM> pins
//
if (IO) {
bitWrite(powResult, pins[i], 1); // output
} else {
bitWrite(powResult, pins[i], 0); // input
} // if-else
//
} // if
//
} // for
//
return (powResult);
//
} // makeBitMaskRange()
uint32_t makeBitMaskRangeNonClobber(uint8_t pins[], uint8_t pinCount, bool IO) {
//
uint8_t val = 0;
uint32_t powResult = getAllPinDirections();
//
for (uint8_t i = 0; i < pinCount; i++) {
//
val = pins[i];
//
if ( ((val < 23) || (val > 25)) && ((val < 29) || (val > 31)) ) { // <SYSTEM> pins
//
if (IO) {
bitWrite(powResult, pins[i], 1); // output
} else {
bitWrite(powResult, pins[i], 0); // input
} // if-else
//
} // if
//
} // for
//
return (powResult);
//
} // makeBitMaskRangeNonClobber()
uint32_t makePutMask(uint8_t vals[], uint8_t pinVals) {
//
uint32_t powResult;
//
for (uint8_t i = 0; i < pinVals; i++) {
//
if ( ((i < 23) || (i > 25)) && ((i < 29) || (i > 31)) ) { // <SYSTEM> pins
//
if (vals[i]) {
bitWrite(powResult, i, 1); // output
} else {
bitWrite(powResult, i, 0); // input
} // if-else
//
} // if
//
} // for
//
return (powResult);
//
} // makePutMask()
void diagnosePinDir() {
//
for (uint8_t i = 0; i < 30; i++) {
//
if (i == 8 || i == 16 || i == 24) Serial1.println();
//
Serial1.print("GPIO");
Serial1.print(i);
Serial1.print(": ");
//
if (i <= 9) Serial1.print(" ");
//
Serial1.print(gpio_get_function(i));
Serial1.print(" ");
Serial1.print(gpio_get_dir(i));
Serial1.print(" ");
//
} // for
//
Serial1.println();
//
} // diagnosePinDir()
void setAllDigital() {
//
for (uint8_t i = 0; i < 31; i++) {
//
if ( ((i < 23) || (i > 25)) && ((i < 29) || (i > 31)) ) { // <SYSTEM> pins
//
gpio_set_function(i, GPIO_FUNC_SIO);
_gpio_init(i); // original written as: gpio_init(), but not accepted on <wokwi.com>
//
} // if
//
} // for
//
} // setAllDigital()
void setAllOutput() {
//
gpio_set_dir_all_bits(makeBitMaskOutAll());
setOE(makeBitMaskOutAll());
//
} // setAllOutput()
void setAllInput() {
//
gpio_set_dir_all_bits(makeBitMaskInAll());
setOE(makeBitMaskInAll());
//
} // setAllInput()
void setRangeDigital(uint8_t pins[], uint8_t pinCount) {
//
uint8_t val = 0;
//
for (uint8_t i = 0; i < pinCount; i++) {
//
val = pins[i];
//
if ( ((val < 23) || (val > 25)) && ((val < 29) || (val > 31)) ) { // <SYSTEM> pins
//
gpio_set_function(pins[i], GPIO_FUNC_SIO);
_gpio_init(pins[i]); // original written as: gpio_init(), but not accepted on <wokwi.com>
//
} // if
//
} // for
//
} // setRangeDigital()
void setRangeOutput(uint8_t pins[], uint8_t pinCount) {
//
gpio_set_dir_all_bits(makeBitMaskRange(pins, pinCount, 1));
setOE(makeBitMaskRange(pins, pinCount, 1));
//
} // setRangeOutput()
void setRangeInput(uint8_t pins[], uint8_t pinCount) {
//
gpio_set_dir_all_bits(makeBitMaskRange(pins, pinCount, 0));
setOE(makeBitMaskRange(pins, pinCount, 0));
//
} // setRangeInput()
void setPortRange(uint8_t startPin, uint8_t endPin, bool IO) {
// port direction 0 for input 1 for output:
uint8_t pinCount = countMidNums(startPin, endPin);
//
uint8_t portPins2[pinCount];
for (uint8_t i = startPin; i <= endPin; i++) portPins2[i] = i;
//
if (IO) {
//output
//gpio_set_dir_all_bits(makeBitMaskRange(pins, pinCount, 1)); // Note: -pins- isn't declared here
//setOE(makeBitMaskRange(pins, pinCount, 1)); // Note: -pins- isn't declared here
gpio_set_dir_all_bits(makeBitMaskRange(portPins2, pinCount, 1));
setOE(makeBitMaskRange(portPins2, pinCount, 1));
//
} else {
//input
//gpio_set_dir_all_bits(makeBitMaskRange(pins, pinCount, 0)); // Note: -pins- isn't declared here
//setOE(makeBitMaskRange(pins, pinCount, 0)); // Note: -pins- isn't declared here
gpio_set_dir_all_bits(makeBitMaskRange(portPins2, pinCount, 0));
setOE(makeBitMaskRange(portPins2, pinCount, 0));
//
} // if-else
//
} // setPortRange()
void setPortRangeNonClobber(uint8_t startPin, uint8_t endPin, bool IO) {
// port direction 0 for input 1 for output:
uint8_t pinCount = countMidNums(startPin, endPin);
//
uint8_t portPins2[pinCount];
for (uint8_t i = startPin; i <= endPin; i++) portPins2[i] = i;
//
if (IO) {
//output
//gpio_set_dir_all_bits(makeBitMaskRangeNonClobber(pins, pinCount, 1)); // Note: -pins- isn't declared here
//setOE(makeBitMaskRangeNonClobber(pins, pinCount, 1)); // Note: -pins- isn't declared here
gpio_set_dir_all_bits(makeBitMaskRangeNonClobber(portPins2, pinCount, 1));
setOE(makeBitMaskRangeNonClobber(portPins2, pinCount, 1));
//
} else {
//input
//gpio_set_dir_all_bits(makeBitMaskRangeNonClobber(pins, pinCount, 0)); // Note: -pins- isn't declared here
//setOE(makeBitMaskRangeNonClobber(pins, pinCount, 0)); // Note: -pins- isn't declared here
gpio_set_dir_all_bits(makeBitMaskRangeNonClobber(portPins2, pinCount, 0));
setOE(makeBitMaskRangeNonClobber(portPins2, pinCount, 0));
//
} // if-else
//
} // setPortRangeNonClobber()
uint32_t readAllPorts() {
//
uint32_t bitMask = gpio_get_all();
return (bitMask);
//
} // readAllPorts()
uint32_t readPortRange(uint8_t startPin, uint8_t endPin) {
//
uint32_t portVal = 0;
//
for (uint8_t i = startPin; i <= endPin; i++) {
// The gpio_get() function is used to get the digital state
// of the GPIO pin (0 for low, non-zero for high).
if (gpio_get(i) == 0) {
bitWrite(portVal, i, 0);
} else {
bitWrite(portVal, i, 1);
} // if-else
//
} // for
//
return (portVal);
//
} // readPortRange()
uint32_t readPort1(uint8_t pins[], uint8_t pinCount) {
//
uint32_t portVal = 0;
//
for (uint8_t i = 0; i < pinCount; i++) {
// The gpio_get() function is used to get the digital state
// of the GPIO pin (0 for low, non-zero for high).
if (gpio_get(pins[i]) == 0) {
bitWrite(portVal, i, 0);
} else {
bitWrite(portVal, i, 1);
} // if-else
//
} // for
//
return (portVal);
//
} // readPort1()
void writeAllPorts(uint32_t bitMask) {
//
gpio_put_all(bitMask);
//
} // writeAllPorts()
void writeAllPorts1(uint8_t pinValues[], uint8_t pinValuesCount) {
//
gpio_put_all(makePutMask(pinValues, pinValuesCount));
//
} // writeAllPorts1()
void writePortRange(uint8_t pins[], uint8_t pinCount, uint8_t pinValues[], uint8_t pinValuesCount) {
//
if (pinCount != pinValuesCount) return;
//
for (uint8_t i = 0; i < pinCount; i++) {
// <SYSTEM> pins
if ( ((i < 23) || (i > 25)) && ((i < 29) || (i > 31)) ) gpio_put(pins[i], pinValues[i]);
//
} // for
//
} // writePortRange()
void writePortRange1(uint8_t startPin, uint8_t endPin, uint8_t pinValues[], uint8_t pinValuesCount) {
//
uint8_t pinCount = countMidNums(startPin, endPin);
uint8_t portPins2[pinCount];
//
for (uint8_t i = startPin; i <= endPin; i++) portPins2[i] = i;
//
if (pinCount != pinValuesCount) return;
//
for (uint8_t i = startPin; i <= endPin; i++) gpio_put(portPins2[i], pinValues[i]);
//
} // writePortRange1()
uint32_t reverseBits(uint32_t inBits) {
//
uint32_t outBits = 0;
//
for (uint8_t i = 0; i < 31; i++) bitWrite(outBits, 31 - i, bitRead(inBits, i));
//
return (outBits);
//
} // reverseBits()
void checkBits(uint8_t bInput, bool lineEnd) {
//00011100011111111111111000000000
//
Serial1.print("Bit0: ");
if (bitRead(bInput, 0)) {
Serial1.print("True ");
} else {
Serial1.print("False ");
} // if-else
//
Serial1.print("Bit1: ");
if (bitRead(bInput, 1)) {
Serial1.print("True ");
} else {
Serial1.print("False ");
} // if-else
//
Serial1.print("Bit2: ");
if (bitRead(bInput, 2)) {
Serial1.print("True ");
} else {
Serial1.print("False ");
} // if-else
//
Serial1.print("Bit3: ");
if (bitRead(bInput, 3)) {
Serial1.print("True ");
} else {
Serial1.print("False ");
} // if-else
//
Serial1.print("Bit4: ");
if (bitRead(bInput, 4)) {
Serial1.print("True ");
} else {
Serial1.print("False ");
} // if-else
//
Serial1.print("Bit5: ");
if (bitRead(bInput, 5)) {
Serial1.print("True ");
} else {
Serial1.print("False ");
} // if-else
//
Serial1.print("Bit6: ");
if (bitRead(bInput, 6)) {
Serial1.print("True ");
} else {
Serial1.print("False ");
} // if-else
//
Serial1.print("Bit7: ");
if (bitRead(bInput, 7)) {
Serial1.print("True ");
} else {
Serial1.print("False ");
} // if-else
//
if (lineEnd) Serial1.println();
//
} // checkBits()
void printBinary8(uint8_t inByte, bool lineEnd, bool MSB) {
//
if (MSB) {
for (uint8_t b = 7; b >= 0; b--) Serial1.print(bitRead(inByte, b)); //bit 7-0
} else {
for (uint8_t b = 0; b < 8; b++) Serial1.print(bitRead(inByte, b)); //bit 0-7
} // if-else
//
if (lineEnd) Serial1.println();
//
} // printBinary8()
void printBinary32(uint32_t inByte, bool lineEnd, bool MSB) {
//
if (MSB) {
for (uint8_t b = 31; b >= 0; b--) Serial1.print(bitRead(inByte, b)); //bit 31-0
} else {
for (uint8_t b = 0; b < 32; b++) Serial1.print(bitRead(inByte, b)); //bit 0-31
} // if-else
//
if (lineEnd) Serial1.println();
//
} // printBinary32()
// --------------------------------------------------------------------------------------
void setup() {
//
Serial1.begin(115200);
//
/* *** NOTE: in the REAL world, the SERIAL MUST BE >>> Serial.xx() <<< -NOT- Serial1.xx() **** */
/* *** NOTE: in the REAL world, the SERIAL MUST BE >>> Serial.xx() <<< -NOT- Serial1.xx() **** */
/* *** NOTE: In the REAL world, the SERIAL MUST BE >>> Serial.xx() <<< -NOT- Serial1.xx() **** */
//
// WARNING: WHITOUT THIS FOLLOWING LINE OF CODE, the serial monitor does not work!!!
//while (! Serial); // WARNING: WHITOUT THIS LINE OF CODE, the serial monitor does not work!!!
// WARNING: WHITOUT THE PREVIOUS LINE OF CODE, the serial monitor does not work!!!
//
/* *** NOTE: in the REAL world, the SERIAL MUST BE >>> Serial.xx() <<< -NOT- Serial1.xx() **** */
/* *** NOTE: in the REAL world, the SERIAL MUST BE >>> Serial.xx() <<< -NOT- Serial1.xx() **** */
/* *** NOTE: in the REAL world, the SERIAL MUST BE >>> Serial.xx() <<< -NOT- Serial1.xx() **** */
//
Serial1.println("setup() ended...\n");
//
} // setup()
void loop() {
//
delay(10);
//
} // loop()