Mixing I/O in a bank of pins and using pin aliases on PSoC5LP

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
KyTr_1955226
Level 6
Level 6
250 sign-ins 10 likes given 50 solutions authored

Hi all, I have a question about if what I want to do is possible or not.

I'm writing some keypad code for PSoC that I want to be flexible, allowing me to assign functions to any arbitrary key in my bank of keypad lines.  Another wrinkle is that I also need to be able to assign any of these pins from Input to output at runtime (some keypads have small status LEDs that the microcontroller must drive).  I have a couple questions about how to accomplish this:

My PSoC hardware for this is configured as such:

pastedImage_0.png

1) My goal is I want to be able to pass the PSoC a configuration via serial that will configure these pins to support any combination of inputs/outputs needed, as well as assign each pin to the desired function.  From my understanding I can simply change the drive mode of the pin to strong drive and it will reconfigure as an output correct?  In this case, I assume the Status Register bit for that line will read the output level?

2) For setting individual pins as outputs, it would make things much easier if I could create an array of pin aliases.  This way if I have the number (1-14) of the pin that is supposed to be an output, I could simply access it via the array and set the drive mode to turn it to an output:

const uint32_t Keypad_PinArray[14] = {Kpd_0, Kpd_1,Kpd_2, Kpd_3, Kpd_4, Kpd_5, Kpd_6, Kpd_7, Kpd_8, Kpd_9, Kpd_10, Kpd_11, Kpd_12, Kpd_13};

uint8_t output_pin = 12;      /*Pin # 1-14 => PinArray 0-13*/

CyPins_SetPinDriveMode(Kpd_PinArray[output_pin-1],CY_PINS_DM_STRONG);

It looks like CyPins_SetPinDriveMode is looking for a uint32_t for the pin argument, so can I just drop the Kpd_# macros into my uint32_t and be OK?

I'd just like to confirm that this will work as I am expecting, and if not, is there a way to accomplish what I'm looking to do?

Thanks!

0 Likes
1 Solution
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

Reading your description I'm not sure if I understand what you are planning for.

From the name "KeyPad", I'd imagine that all those pins are connected to input switches.

And status of some (or one) input will be reflected to output.

Or do you want to  assign something like below?

=============

kpd_0 input

kpd_1 output

kpd_2 output

kpd_3 input

kpd_4 input

=============

Anyway, for the time being, I hope that one safe information I can refer to is

the Figure 19-1. GPIO Block Diagram from the PSoC 5LP Architecture TRM.

GPIO_Block_Diagram.JPG

The "CyPins_SetPinDriveMode" only takes care of PRTDM0, PRTDM1, PRTDM2.

So you need to specify if the pin takes the value from PRTDR or Digital System Output

by specifying PRTBYP and/or PRTBIE (for Bidrectional Control).

moto

View solution in original post

0 Likes
8 Replies
odissey1
Level 9
Level 9
First comment on KBA 1000 replies posted 750 replies posted

KyTr,

It doesn't seems that the pins are connecting to any hardware (apart a Status Regs), and all you need is to read/write pins state thru API calls. You can drop pins on the schematic, disable the hardware connection (green line) and access Pins via API calls (read/write). No Status Regs are needed.

/odissey1

0 Likes

odissey,

I want the status registers so I can quickly put together an uint16 that represents my entire keypad state rather than putting it together by reading each pin in software individually.  I will also have a debouncer component on the input in the final design since there's no discrete debouncing hardware (I just haven't added it in yet).  I'm just making sure the logic is sound for changing the pin drive mode for lines that need to be output rather than input.

The layout of the keypad buttons will be arbitrary, so I need to be able to assign different pre-programmed functions to any one of those lines.  I'm going to go with reading in a uint16 (the two status registers) that represents the entire keypad and generating a mask for each pin function based on config input received via serial.  It will then be validated, saved to NVM, then loaded on subsequent bootups).

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

Reading your description I'm not sure if I understand what you are planning for.

From the name "KeyPad", I'd imagine that all those pins are connected to input switches.

And status of some (or one) input will be reflected to output.

Or do you want to  assign something like below?

=============

kpd_0 input

kpd_1 output

kpd_2 output

kpd_3 input

kpd_4 input

=============

Anyway, for the time being, I hope that one safe information I can refer to is

the Figure 19-1. GPIO Block Diagram from the PSoC 5LP Architecture TRM.

GPIO_Block_Diagram.JPG

The "CyPins_SetPinDriveMode" only takes care of PRTDM0, PRTDM1, PRTDM2.

So you need to specify if the pin takes the value from PRTDR or Digital System Output

by specifying PRTBYP and/or PRTBIE (for Bidrectional Control).

moto

0 Likes
lock attach
Attachments are accessible only for community members.
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

Although I may be totally missing the point,

I wrote a sample from what I (think) read from your description.

I used CY8CKIT-059 (CY8C5888LTI-LP097)

The schematic is

000-schematic.JPG

Pin assignment

001-pin-list.JPG

When the program is started

002-program-started.JPG

If we connect a switch which short the pin to GND, key 0 will print '0' on the serial terminal.

key 1 will print '1' and so on.

Functions available to be assigned to keys are

003-function.JPG

Typing 'help' to the prompt will show the command list

003-help.JPG

Now re-assigning functions to keys

004-assigning.JPG

Then typing 'list" will show the current assignment

004-list.JPG

If we short key 1 to GND, LED on the board turns on.

If we short key 5 to GND, '9' will be written to the serial terminal.

and typing 'reset' will reset the pin assignment to the initial setting.

005-reset-list.JPG

main.c

===============

#include "project.h"

#include "stdio.h"

#include "tty_utils.h"

#define LED_ON  1

#define LED_OFF 0

#define NUM_KEY 14

void do_0(void)          { print("0") ; }

void do_1(void)          { print("1") ; }

void do_2(void)          { print("2") ; }

void do_3(void)          { print("3") ; }

void do_4(void)          { print("4") ; }

void do_5(void)          { print("5") ; }

void do_6(void)          { print("6") ; }

void do_7(void)          { print("7") ; }

void do_8(void)          { print("8") ; }

void do_9(void)          { print("9") ; }

void do_A(void)          { print("A") ; }

void do_B(void)          { print("B") ; }

void do_C(void)          { print("C") ; }

void do_D(void)          { print("D") ; }

void do_E(void)          { print("E") ; }

void do_F(void)          { print("F") ; }

void do_LED_ON(void)     { LED_Write(LED_ON) ;      }

void do_LED_OFF(void)    { LED_Write(LED_OFF) ;     }

void do_LED_Toggle(void) { LED_Write(!LED_Read()) ; }

typedef void (*func_ptr_type)(void) ;

typedef struct _key_func_s {

    char *name ;

    func_ptr_type func ;

    char *description ;

} key_func_type ;

key_func_type key_func[] = {

    { "0",      do_0,          "Print '0'"    },

    { "1",      do_1,          "Print '1'"    },

    { "2",      do_2,          "Print '2'"    },

    { "3",      do_3,          "Print '3'"    },

    { "4",      do_4,          "Print '4'"    },

    { "5",      do_5,          "Print '5'"    },

    { "6",      do_6,          "Print '6'"    },

    { "7",      do_7,          "Print '7'"    },

    { "8",      do_8,          "Print '8'"    },

    { "9",      do_9,          "Print '9'"    },

    { "A",      do_A,          "Print 'A'"    },

    { "B",      do_B,          "Print 'B'"    },

    { "C",      do_C,          "Print 'C'"    },

    { "D",      do_D,          "Print 'D'"    },

    { "E",      do_E,          "Print 'E'"    },

    { "F",      do_F,          "Print 'F'"    },

    { "ON",     do_LED_ON,     "Turn LED ON"  },

    { "OFF",    do_LED_OFF,    "Turn LED OFF" },

    { "TOGGLE", do_LED_Toggle, "Toggle LED"   },

    { 0, 0, 0 }

} ; 

key_func_type *key[NUM_KEY] = {

    &key_func[0],

    &key_func[1],

    &key_func[2],

    &key_func[3],

    &key_func[4],

    &key_func[5],

    &key_func[6],

    &key_func[7],

    &key_func[8],

    &key_func[9],

    &key_func[10],

    &key_func[11],

    &key_func[12],

    &key_func[13]

} ;

void help(void) ;

void set_key(void) ;

void clear_key(void) ;

void reset_keys(void) ;

void list_keys(void) ;

void list_functions(void) ;

key_func_type command_list[] = {

    { "help",     help,           "Show this list"              },

    { "set",      set_key,        "Assing function to a key"    },

    { "clear",    clear_key,      "Clear function from a key"   },

    { "reset",    reset_keys,     "Reset to default key assign" },

    { "list",     list_keys,      "Show current key assign"     },

    { "function", list_functions, "Show available fucntions"    },

    { 0,          0,              0                             }

} ;

void str2upper(char *str)

{

    while(str && *str) {

        if (('a' <= *str)&&(*str <= 'z')) {

            *str -= 'a' - 'A' ;

        }

        str++ ;

    }

}

void str2lower(char *str)

{

    while(str && *str) {

        if (('A' <= *str)&&(*str <= 'Z')) {

            *str += 'a' - 'A' ;

        }

        str++ ;

    }

}

void init_hardware(void)

{

    tty_init() ;

    CyGlobalIntEnable; /* Enable global interrupts. */

}

void help(void)

{

    int i ;

    print("  command  :         description \n") ;

    print("-----------+----------------------------\n") ;

    for (i = 0 ; command_list.name ; i++ ) {

        sprintf(str, "%10s : ", command_list.name) ;

        print(str) ;

        print(command_list.description) ;

        print("\n") ;

    }

    print("----------------------------------------\n") ;

}

void list_keys(void)

{

    int i ;

    print("Key Assignment List\n") ;

    print("Key :   Name  : Description\n") ;

    print("----+---------+-------------\n") ;

    for (i = 0 ; i < NUM_KEY ; i++ ) {

        sprintf(str, "  %X : ", i) ;

        print(str) ;

        if (key == 0) {

            sprintf(str, "Key %X is not assigned\n", i) ;

            print(str) ;

        } else {

            sprintf(str, "%7s : ", key->name) ;

            print(str) ;

            print(key->description) ;

            print("\n") ;

        }

    }

    print("----------------------------\n") ;

}

void list_functions(void)

{

    int i ;

    print("Available Function List\n") ;

    print("   Name  : Description\n") ;

    print("---------+-------------\n") ;

    for (i = 0 ; key_func.name ; i++) {

        sprintf(str, "%7s : ", key_func.name) ;

        print(str) ;

        print(key_func.description) ;

        print("\n") ;

    }

    print("-----------------------\n") ;   

}

void set_key(void)

{

    int i ;

    int pin_number = 0 ;

    while(get_string() == 0) ; /* get pin number */

    sscanf(str, "%x", &pin_number) ;

    if ((pin_number < 0) || (pin_number >= NUM_KEY)) {

        sprintf(str, "key number [%x] is out of range (0 - %x)\n",

            pin_number, (NUM_KEY - 1)) ;

        print(str) ;

        return ;

    }

   

    while(get_string() == 0) ; /* get function */

    str2upper(str) ;

    i = 0 ;

    while(key_func.name) {

        if (strcmp(str, key_func.name) == 0) {

            sprintf(str, "Key[%x] <= %s : %s\n",

                pin_number, key_func.name, key_func.description) ;

            print(str) ;

            key[pin_number] = &key_func ;

            return ;

        }

        i++ ;

    }

    print("Undefined function : ") ;

    print(str) ;

    print("\n") ;

}

void clear_key(void)

{

    int pin_number = 0 ;

    int i ;

    while(get_string() == 0) ; /* get pin number or "all" */

    str2upper(str) ;

    if (strcmp(str, "ALL") == 0) {

        for (i = 0 ; i < NUM_KEY ; i++ ) {

            key = 0 ;

        }

    } else {

        sscanf(str, "%x", &pin_number) ;

        if ((0 <= pin_number)&&(pin_number < NUM_KEY)) {

            key[pin_number] = 0 ;

        }

    }

}

void reset_keys(void)

{

    int i ;

    for (i = 0 ; i < NUM_KEY ; i++ ) {

        key = &key_func ;

    }

}

void do_command(char *cmd)

{

    int i ;

    str2lower(cmd) ;

    for (i = 0 ; command_list.name ; i++ ) {

        if (strcmp(cmd, command_list.name) == 0) {

            command_list.func() ;

            return ;

        }

    }

    print("Unknown command : ") ;

    print(cmd) ;

    print("\n") ;

}

uint16_t get_key_pad(void)

{

    uint8_t hi, lo, value ;

    hi = KpdHi_Read() ;

    lo = KpdLo_Read() ;

    value = (hi << 😎 | lo ;

    return( value ) ;

}

void do_key_pad(void)

{

    static uint16_t prev_key_pad = 0 ;

    uint16_t key_pad ;

    uint16_t mask = 0x01 ;

    int i ;

   

    key_pad = get_key_pad() ;

    if (key_pad != prev_key_pad) { /* some change(s) took place */

        for (i = 0 ; i < NUM_KEY ; i++ ) {

            mask = (0x01 << i) ;

            if (((prev_key_pad & mask) == mask) && ((key_pad & mask) == 0)) { /* key pressed (active Low) */

                if (key) { /* key_function is assigned */

                    key->func() ;

                }

            }

        }

        prev_key_pad = key_pad ;

        CyDelay(100) ; /* instead of debounce */

    }

}

int main(void)

{

    init_hardware() ;

   

    splash("I/O Bank Test") ;

   

    list_keys() ;

    prompt() ;

    for(;;)

    {

        if (get_string()) { /* check for UART command input */

            do_command(str) ;

            prompt() ;

        }     

        do_key_pad() ;

    }

}

===============

moto

moto,

You've basically got the idea.  Our keypads are a little funky.  I have to initialize all the pins as inputs, but a number of our keypads that will be connected to these pins have little status LEDs to be driven from the microcontroller that need to be set as outputs.  On top of this, there is no dedicated ground on the connector to these keypads, so I have to set their respective grounds (the button return line and LED return lines) as outputs at 0.  The trick is that these LED lines and return lines can in theory be on any of the pins, so if I want to make this system generic and configurable I need to be able to set these pins as Strong Drive Outputs at runtime (or whenever a keypad layout is received).

I've actually got keypad code with this feature set that I wrote for PIC24 several years ago, I'm now essentially porting it to PSoC, and needed to clarify how to cleanly switch between inputs/outputs while running.  On PIC is was just TRISx bits I could toggle 1 for in 0 for out, PSoC is a little more in depth with it's options on each pin.

Just to make sure I understand, the PRTBYP and PRTBIE registers are only applicable if I'm doing Bidirectional, correct?

Thanks!

0 Likes
MotooTanaka
Level 9
Level 9
Distributor - Marubun (Japan)
First comment on blog Beta tester First comment on KBA

Hi,

> Just to make sure I understand, the PRTBYP and PRTBIE registers are only applicable if I'm doing Bidirectional, correct?

From the dialog, for controlling OE of the output buffer, we need to control "Bidirectional Control",

but as far as PRTBIE is de-asserted, the pin should act as Input.

Since I have never tested such a trick by myself,

I'd like to ask you to review the chapter of TRM and test it enough,

I'm hoping that it will work though.

moto

0 Likes

Just a nice little cap on this thread, I set the pins as bi-directional open-drain pulled high for my keys, and set my necessary outputs to strong drive via firmware while running and it seems to be all working as expected.  I am reading key inputs and lighting up the necessary LEDs.

I hard coded the keypad configurations (pin numbers) into a testing firmware rather than receiving via serial but from here it should be trivial to take this information in via serial connection.

Thanks for all the input, everyone!

KyTr,

For the manual keyboard it is sufficient to parse pins on a slow time scale (<1kHz). For example, this community component does reading of up to 32 pins (with debouncing) using <50 bus clocks.

ButtonSw32: button switch debouncer component

I recommend to check this component first. Later, the code can be modified for output (by adding some mask), with pins re-assignment performed in software using a lookup table.

The above implementation reads pins by 8-bit port at once. I also have another (unpublished) beta version for randomly assigned individual pins. Surprisingly, for small amount of pins (<16), there is only small difference in performance, compared to block access. I can post it on request.

/odissey1

0 Likes