Page 1 sur 1

[Solved] Control of GPIO pins

Message non luPosté: 19 Nov 2017, 21:47
de Alchemistress
Hello!
I saw Vogtinator's incredible wav player thingy on Omnimaga, and had a rummage through the source code for it, in the hope of controlling some simple electronics with the GPIO pins in the dock connector. I also looked through the Hackspire page on the memory addresses of the GPIOs. The page says that each register is a word, but that only bits 0-7 are used. I couldn't find anything which said how many bits are in a word on a Ti-nspire. From Vogtinator's program it seems that the registers have 32 bits.
I tried writing a small program to blink an LED connected to GPIO4. It didn't work, sadly, and I can't figure out why. My code isn't the most compact, but C is new to me, and I don't care that much about neatness, for now I just want my lights to blink.
Here's the mess I created:
Code: Tout sélectionner
#include <nspireio/nspireio.h>
#include <stdint.h>
#include <math.h>
#include <libndls.h>

#define NSPIRE_WORD uint32_t
#define GPIO_SEC_0 (NSPIRE_WORD) 0x90000000
#define GPIO_SEC_1 (NSPIRE_WORD) 0x90000040
#define GPIO_SEC_2 (NSPIRE_WORD) 0x90000080
#define GPIO_SEC_3 (NSPIRE_WORD) 0x900000C0
#define GPIO_DIRECTION_BIT (NSPIRE_WORD) 0x10
#define GPIO_OUT_BIT (NSPIRE_WORD) 0x14
#define GPIO_IN_BIT (NSPIRE_WORD) 0x18
#define OUT 0
#define IN 1
#define LOW 0
#define HIGH 1

NSPIRE_WORD* getRegPtr(int sectionNum, int offset);
void setPinDirection(int GPIO, int direction);
void setOutValue(int GPIO, int value);
int readValue(int GPIO);

int main() {
   nio_console console;
   nio_init(&console, NIO_MAX_COLS, NIO_MAX_ROWS, 0, 0, NIO_COLOR_BLACK, NIO_COLOR_WHITE, TRUE);
   
   setPinDirection(4, OUT);
   
   setOutValue(4, HIGH);
   nio_fprintf(&console, "GPIO4 is now HIGH.\n");
   sleep(2000);
   
   setOutValue(4, LOW);
   nio_fprintf(&console, "GPIO4 is now LOW.\n");
   sleep(2000);
   
   nio_fprintf(&console, "Done!\n");
   wait_key_pressed();
   
   nio_free(&console);
   
   return 0;
}

NSPIRE_WORD* getRegPtr(int sectionNum, int offset) {
   if(sectionNum == 0) {
      return (NSPIRE_WORD*) (GPIO_SEC_0+offset);
   }
   else if(sectionNum == 1) {
      return (NSPIRE_WORD*) (GPIO_SEC_1+offset);
   }
   else if(sectionNum == 2) {
      return (NSPIRE_WORD*) (GPIO_SEC_2+offset);
   }
   else {
      return (NSPIRE_WORD*) (GPIO_SEC_3+offset);
   }
}

void setPinDirection(int GPIO, int direction) {
   int sectionNum = floor(GPIO/8);
   int bitNum = GPIO%8;
   
   NSPIRE_WORD* regPtr = getRegPtr(sectionNum, GPIO_DIRECTION_BIT);
   NSPIRE_WORD gpioDirectionReg = *regPtr;
   
   if(direction == OUT) {
      gpioDirectionReg &= ~(0x00000001<<bitNum);
   }
   else {
      gpioDirectionReg |= 0x00000001<<bitNum;
   }
   
   *regPtr = gpioDirectionReg;
}

void setOutValue(int GPIO, int value) {
   int sectionNum = floor(GPIO/8);
   int bitNum = GPIO%8;
   
   NSPIRE_WORD* regPtr = getRegPtr(sectionNum, GPIO_OUT_BIT);
   NSPIRE_WORD gpioOutputReg = *regPtr;
   
   if(value == LOW) {
      gpioOutputReg &= ~(0x00000001<<bitNum);
   }
   else {
      gpioOutputReg |= 0x00000001<<bitNum;
   }
   
   *regPtr = gpioOutputReg;
}

int readValue(int GPIO) {
   int sectionNum = floor(GPIO/8);
   int bitNum = GPIO%8;
   
   NSPIRE_WORD gpioInputReg = *getRegPtr(sectionNum, GPIO_IN_BIT);
   
   return (gpioInputReg>>bitNum)&0x00000001;
}


Horrid, isn't it. I'd be very grateful if someone could enlighten me! I may have done something stupid, in which case you're welcome to textually scream at me.

Re: Control of GPIO pins

Message non luPosté: 19 Nov 2017, 22:17
de Vogtinator
I couldn't find anything which said how many bits are in a word on a Ti-nspire. From Vogtinator's program it seems that the registers have 32 bits.


Yup, they are.

To rule out software errors, you can replace your code with just a few lines:

Code: Tout sélectionner
*(volatile uint32_t*)(0x90000010) &= ~(1<<4);
while(!any_key_pressed()) {
    *(volatile uint32_t*)(0x90000014) &= ~(1<<4);
    sleep(2000);
    *(volatile uint32_t*)(0x90000014) |= 1<<4;
    sleep(2000);
}


Your code works fine in firebird though (can't test on a real calc today, maybe tomorrow), so I suspect a hardware issue instead.
You could try to measure the voltage on the pin instead.

It's also useful to be able to change GPIO vals at will, you can either write your own program for that or use linuxloader2's poke and peek commands to write and read 32bit words anywhere.

Re: Control of GPIO pins

Message non luPosté: 19 Nov 2017, 22:43
de Alchemistress
Thanks a lot! I stuck volatile in the necessary places in my code, but no dice. I tried yours, too. Also nothing, so you must be right about the hardware issue. Would there be any difference in the pinout or code for the CX non-CAS?

Re: Control of GPIO pins

Message non luPosté: 19 Nov 2017, 22:51
de Vogtinator
Alchemistress a écrit:Thanks a lot! I stuck volatile in the necessary places in my code, but no dice. I tried yours, too. Also nothing, so you must be right about the hardware issue. Would there be any difference in the pinout or code for the CX non-CAS?


No. You can try running the toggle in an endless loop and measuring the pin without anything attached next, that's the method I used for mapping the user-reachable GPIOs.

Re: Control of GPIO pins

Message non luPosté: 19 Nov 2017, 22:54
de critor
Which pin are you using ?
On the picture below, are you counting from the right or from the left ?
8882

The problem is TI is counting from the right and Hackspire from the left.
Which can be quite confusing when some pin labels are visible, as it's the case on CX calculators.

Re: Control of GPIO pins

Message non luPosté: 19 Nov 2017, 23:12
de Alchemistress
That is mildly infuriating. Thank you, I have no idea how long it would've taken me to realise something that simple. I was counting from the 1 marked on the connector's PCB; from the right in the picture. Everything seems to work now!