CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug Reports on this forum. Send them to

How to use #pin_select

Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message

Joined: 07 Apr 2014
Posts: 1

View user's profile Send private message

How to use #pin_select
PostPosted: Thu Apr 21, 2016 5:30 pm     Reply with quote

In my project in setting I2c through CCS WIZARD I have this error when compiling.....

Option invalid. Wrong pin for H/W.

This my code:
file I2C.h

#include <16LF1704.h>
#device ADC=10
#use delay(internal=32MHz)

#define Device_SDA PIN_C1
#define Device_SLC  PIN_C0

#use i2c(Slave,Slow,sda=Device_SDA,scl=Device_SLC,address=0x10)

file I2C.c

#include <I2C.h>

void main()

      //TODO: User Code

PCM programmer

Joined: 06 Sep 2003
Posts: 21065

View user's profile Send private message

PostPosted: Thu Apr 21, 2016 8:47 pm     Reply with quote

Put this above the #use i2c() statement:
#pin_select SCL1OUT = PIN_C0
#pin_select SCL1IN  = PIN_C0

#pin_select SDA1OUT = PIN_C1
#pin_select SDA1IN  = PIN_C1

Joined: 11 Mar 2010
Posts: 15742

View user's profile Send private message

PostPosted: Fri Apr 22, 2016 4:33 am     Reply with quote

This is one that is approaching 'FAQ' status. Perhaps ought to be a sticky at the top of the forum. It is now!... Smile

PIC's have three different ways of selecting pins that peripherals go to:

The first (oldest), is in some cases individual peripherals can be set to two different sets of pins using a fuse. So you have chips with fuses like 'ALTI2C1', that sets the I2C1 peripheral to use the alternate pins.
Then there were chips with the 'first generation' re-mappable peripherals, where there is a single configuration bit that moves a peripheral to another set of pins (exactly like the fuse, but accessible in software).
Then there is the latest version 'Peripheral Pin Select' (PPS).

It is 'PPS' chips that #PIN_SELECT is for.

On these there are a number of pins, that support 're-mappable peripherals' (normally shows as 'RP...' in the pin diagrams, and a number of peripherals that can be moved to these. On these, you must tell the compiler what pins the peripheral is using before setting the peripheral up.

Just to expand on PCM_programmer's answer, I'd also suggest using the peripheral name, rather than the pins in the #use statement. So:

#include <16LF1704.h>
#device ADC=10
#use delay(internal=32MHz)

#pin_select SCL1OUT = PIN_C0
#pin_select SCL1IN  = PIN_C0

#pin_select SDA1OUT = PIN_C1
#pin_select SDA1IN  = PIN_C1

#use i2c(Slave,I2C1,address=0x10)

So this sets the peripheral I2C1 SCL I/O functions to go to PIN_C0 and the SDA to go to PIN_C1.
Then the #use I2C, can talk to the hardware peripheral (I2C1), and it's external connections will be to these pins.

As a comment to the poster at the start of this thread, get rid of 'slow'. A _slave_ does not have a speed in general. The speed is controlled and settable in the master only. Can cause issues in the configuration.

Now to expand for other devices. What I/O devices can use this?.

This depends on your chip. Data sheet, and look at the header file for the chip. So (for instance), the chip header may well say something like:

////////////////////////////////////////////////////////////////// PIN_SELECT
// #pin_select function=pin
// Valid Pins:
//    PIN_B10,PIN_B11,PIN_B12,PIN_B13,PIN_B14,PIN_B15,PIN_A0,PIN_A1
// Input Functions:
// Output Functions:

So this chip has a huge array of peripherals that can be used this way (four interrupt pins, four CCP's, Uart1, Uart2, SSP2 etc., and a lot of pins that can be used.

To setup the UART for pins B11 (RX) and B10 (TX), the syntax is:

#USE RS232 (UART1, BAUD=115200, ERRORS)
//You should always use 'ERRORS' unless you are adding code to
//handle hardware ERRORS yourself

In addition to this, it is possible if required to 'dynamically' change the mapping later 'in code'. This is only needed if you have some specific reason to 'change things'. So (perhaps) you want to do a serial receive on another set of pins for a little while, and want the hardware UART on these.

Things needed:

1) Map the peripherals to the 'default' setting in the setup as shown.
2) Have the fuse NOIOL1WAY. This allows the settings to be used more than once after the chip boots.
3) Then you can change mappings 'in code', so (for instance) to move the above UART to pins B12, and B13:

    //Inside your code when wanted
    putc('X'); //this will be using the default pins
    delay_ms(50); //ensure byte has finished sending.

    pin_select("U1RX", PIN_B12, TRUE, FALSE);
    pin_select("U1TX", PIN_B13, FALSE, TRUE);

    //Now sent using B13

The 'TRUE' and 'FALSE' stuff is to do with unlocking the pin. Basically if you are doing a number of changes, then unlock on the first command, and lock up again on the last one. The 'TRUE' on the first command unlocks, then the 'FALSE says "don't lock back up", while on the next command the pins are already unlocked (so 'FALSE' for the unlock), but then lock back up when finished (final 'TRUE'). Keeping the pins locked when not being changed, avoids accidental unwanted changes..... Very Happy

The default if these are omitted is to unlock and re-lock every time, but this takes longer.

There are sometimes some oddities that need to be carefully watched for.
An example here is the clock shown in the I2C setup, where there is both an 'in' and 'out' separated internally, and both have to be mapped to the single SCL pin if the peripheral is to work as expected. This is mentioned in the data sheet, so 'beware' and make sure you know what has to be mapped where....

One 'caveat' to add to this, applies with bootloaders.
If you have a bootloader, and it uses a PPS peripheral (so maps anything
with PPS), you need to ensure the NOIOL1WAY fuse is selected. Otherwise
your main code will not be able to change the pin settings.
The IOL1WAY fuse means that things can be set only once. Problem is if
the bootloader is setting them, then the 'main' code can't set them again....

Joined: 17 Sep 2003
Posts: 82
Location: Atlanta, GA, USA

View user's profile Send private message

PostPosted: Fri Oct 18, 2019 8:04 am     Reply with quote

The above shows you how to setup mappable PPS chips for I2C and RS232. Here are some others for this sticky post.

One might expect to use #pin_select CP4OUT=PIN_G3 for example, but I have not been able to get this to work on V5 compilers. Here is an example of how I set two PWM outputs on pins G3 and G4:
#use pwm(CCP4, output=PIN_G3, TIMER=2, FREQUENCY=80, DUTY=50, STREAM=PWM_FAN)      // Fan ECM
#use pwm(CCP5, output=PIN_G4, TIMER=6, FREQUENCY=250, DUTY=50, STREAM=PWM_PUMP)   // Variable speed pump
PWM working values are set like this:
pwm_set_duty_percent(PWM_FAN,mDC);                        // Set the fan's PWM value
pwm_set_duty_percent(PWM_PUMP,1000);                  // Set the pump's PWM value

NOTE: the pwm_set_duty_percent() uses a 16 bit integer with a range of 0-1000 with an implied decimal for setting the value. To set the PWM to 85.7%, you pass 857.

This snippet from a header allows me to use the internal 5 bit DAC or an external SPI 8 bit DAC. A ProjectConfig.h file defines which DAC to use and this header and the code snippets below compile appropriately.
#if defined(USE_DAC_INTERNAL)
// DAC does NOT use PPS on this chip, but does have two channels
#define DAC_CHAN            DAC_OUTPUT                  // Define which channel to use ("DAC_OUTPUT" channels are defined in the device header file)
#elif defined(USE_DAC_MCP48FVB02)
///// External SPI DAC /////
// PPS definitions //
#pin_select SCK2OUT = PIN_D6
#pin_select SCK2IN = PIN_D6
#pin_select SDO2 = PIN_D4
#pin_select SDI2 = PIN_D5
#use spi(SPI2,BITS=8,MODE=0, BAUD=1000000)
#define DAC_CS               PIN_D1                              // Chip select
#define DAC_LATCH            PIN_D0                              // The external DAC needs a latch signal

GOTCHA: Yes, you must define SCK2OUT and SCK2IN as the same pin when you are an SPI Master!

With the above header file compiled for use with the internal DAC, setting a value is as simple as the following (value 0-31):
setup_dac(DAC_VSS_VDD | DAC_CHAN);                           // Setup DAC, referenced to chip power & ground. Vref+ cannot be used on this target.
dac_write(18);                                             // Set the internal DAC to 18

SPI is setup similar to I2C in the header above. As an example, here is a read function for a MCP48FVB02 SPI device.
UINT16 MCP48FVB02_Generic_Read(UINT8 iWhere) {
   UINT8      iLow,iHigh;                                          // Some 8 bit holder variables to make things easy
   iWhere <<= 3;                                                // Shift the address up 3 bits
   iWhere |= 0x07;                                             // Put two 1s to send the read command, with a blank for the CMDERR bit

   output_low(DAC_CS);                                          // Select the SPI DAC
   iHigh=spi_read2(0);                                             //read a value from the SPI device
   iLow=spi_read2(0);                                             //read a value from the SPI device
   output_high(DAC_CS);                                          // Deselect the SPI DAC


For cross-platform compatibility, I have a header file that defines the following (and much more) for CCS use as:
#define UINT8      unsigned int8
#define UINT16      unsigned int16
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

Powered by phpBB © 2001, 2005 phpBB Group