S1JA - R_PFS->Pmn Port functions

I am trying to find a way to set the GPIO Port output high or low(1 or 0) with direct bit access, reading the S1JA Manual it seems that you can do this with the following code : 

R_PFS->P205PFS_b.PODR = 1;  // High

R_PFS->P205PFS_b.PODR = 0; // Low

None of these seem to work, I was wondering if anyone can assist me in doing this.

PS. I am writing my own driver for a device connected to different pins on different ports and therefore need to be able to set these high and low directly, I want bit access as I don't want to affect other pins on the same ports.

Regards,

Ronald

  • Okay, for anyone interested this is what I found so far, you can do it with the code supplied, as long as you have enabled the PortFunctionSelect Write enable first, so you must the following code first :
    R_PMISC->PWPR_b.BOWI = 0;
    R_PMISC->PWPR_b.PFSWE = 1;
    R_PFS->P205PFS_b.PODR = 0; // Low, 1 = high

    It appears you only have to do this once in your code, however leaving it on I would assume could get risky, but this works for me for now, if someone has a better solution please post it here.

    Regards,
    Ronald
  • In reply to Ghost:

    Ronald,

    There are actually 3 ways to toggle an I/O port pin.

    The code below shows the 3 ways.  Running this code on the S1JA-TB toggles the LED, attached to port 2.5.

     

     

    You have discovered yourself the protection function of the PFS registers.

    Hope this is of interest.

     

    Regards

    Richard

     

    /* HAL-only entry function */
    #include "hal_data.h"

    typedef enum e_pwpr_access
    {
        PFS_WRITE_DISABLE = 0,       ///< Disable PFS write access
        PFS_WRITE_ENABLE  = 1        ///< Enable PFS write access
    } pwpr_access_t;

    void user_ioport_pfs_access (pwpr_access_t value);


    void hal_entry(void)
    {
        /* TODO: add your own code here */


        /* Ensure P2.5 is an output pin */
        R_IOPORT2->PCNTR1 |= 0x00000020;    // b[31:16] Output data, b[15:0] input / output select


        while(1)
        {
            for( uint8_t loop=0; loop<3; loop++)
            {
                /* Toggle via PFS */
                /* ************** */
                user_ioport_pfs_access( PFS_WRITE_ENABLE );

                R_PFS->P205PFS_b.PODR = 1;  // High
                R_BSP_SoftwareDelay(250, BSP_DELAY_UNITS_MILLISECONDS); // delay so user can see the LED change state

                R_PFS->P205PFS_b.PODR = 0;  // Low
                R_BSP_SoftwareDelay(250, BSP_DELAY_UNITS_MILLISECONDS); // delay so user can see the LED change state

                user_ioport_pfs_access( PFS_WRITE_ENABLE );
            }

            R_BSP_SoftwareDelay(2000, BSP_DELAY_UNITS_MILLISECONDS); // long delay so user can see the the change in toggle method


            for( uint8_t loop=0; loop<6; loop++)
            {
                /* Toggle via PCNTR1 */
                /* ***************** */
                // Set high
                R_IOPORT2->PCNTR1 |= 0x00200000;     // b[31:16] Output data, b[15:0] input / output select
                R_BSP_SoftwareDelay(250, BSP_DELAY_UNITS_MILLISECONDS);

                // Set low
                R_IOPORT2->PCNTR1 &= (uint32_t)~0x00200000;     // b[31:16] Output data, b[15:0] input / output select
                R_BSP_SoftwareDelay(250, BSP_DELAY_UNITS_MILLISECONDS);
            }

            R_BSP_SoftwareDelay(2000, BSP_DELAY_UNITS_MILLISECONDS);


            for( uint8_t loop=0; loop<9; loop++)
            {
                /* Toggle via PCNTR3 */
                /* ***************** */
                // Set high
                R_IOPORT2->PCNTR3 |= 0x00000020;     // b[31:16] Output Reset, b[15:0] Output Set
                R_BSP_SoftwareDelay(250, BSP_DELAY_UNITS_MILLISECONDS);

                // Set low
                R_IOPORT2->PCNTR3 |= 0x00200000;     // b[31:16] Output Reset, b[15:0] Output Set
                R_BSP_SoftwareDelay(250, BSP_DELAY_UNITS_MILLISECONDS);
            }

            R_BSP_SoftwareDelay(2000, BSP_DELAY_UNITS_MILLISECONDS);
        }
    }


    void user_ioport_pfs_access (pwpr_access_t value)
    {
        if (PFS_WRITE_ENABLE == value)
        {
            R_PMISC->PWPR = 0;      //< Clear BOWI bit - writing to PFSWE bit enabled
            R_PMISC->PWPR = 0x40;   //< Set PFSWE bit - writing to PFS register enabled
        }
        else
        {
            R_PMISC->PWPR = 0;      //< Clear PFSWE bit - writing to PFS register disabled
            R_PMISC->PWPR = 0x80;   //< Set BOWI bit - writing to PFSWE bit disabled
        }
    }

  • In reply to Richard:

    Hi Richard,

    Thanks for the reply, I was already aware of the other 2 methods, and as you said I discovered the other one, and this is the one I needed.

    Regards,
    Ronald.
  • In reply to Ghost:

    Hello Ronald,

    I'll just leave a note here that accessing PMISC registers directly without any critical section and counter is not a recommended approach. Here's how IOPORT driver performs locking and unlocking of these registers:

    Use of critical section ensures uninterrupted access for the duration of PMISC access. Reference counter is used to make sure that only the last context to call PFSAccessDisable will actually lock the registers. It's highly recommended that these functions are invoked or recreated in your code to prevent any potential issues associated with different threads/interrupts performing PFS access.

    Regards

  • In reply to Renesas Karol:

    Hi Karol,

    I appreciate the info, and I would like to do it correctly, but I really cannot seem to understand what this code will do effectively, accept prevent writing those registers again if they have been written before and then disabling the writes again when you call the second one, so for me its reasonably simple, I have written a 16x2 Character LCD driver for the S1JA and to achieve this I have to set pins high and low, as well as change them from outputs to inputs (read the Busy Flag) and keep timing going during these steps, no sure thats mostly in the initialization steps but still needed, and for this I found that enabling the direct access like this solved the issue for me to get the LCD working.

    All this said, if you can point me in the direction for the correct method of doing this please I would love to have the knowledge of doing this correctly on Renesas device's I dont like doing this wrong or in a unstable manner.

    Just so you know why I wanted this method, I come from using Microchip products, and accessing the pins like this is as simple as writing to the Latch Register associated with the required pin, and this is what I wanted, as I just ported my LCD driver I wrote.

    Regards,
    Ronald