|
|
View previous topic :: View next topic |
Author |
Message |
wangine
Joined: 07 Jul 2009 Posts: 98 Location: Curtea de Arges, Romania
|
How to set TRIS for single pin without affect port state |
Posted: Wed Sep 09, 2015 1:54 pm |
|
|
I need to buid a driver for a device with I2C protocol , but without use CCS built in I2C function , that because i want to be available for devices without I2C and for diferent clock speed. I want to set TRIS in time of executing program without change the stats of others pins of port .
Code: | // I2C level
typedef enum{
LOW = 0,
HIGH = 1,
}etI2cLevel; |
Code: |
#define SDA_STATE ??????(i want to set tris in or out)
#define SDA_CONF output_bit(xxx_pin, 1)
#define SCK_STATE ??????(i want to set tris in or out)
#define SCK_CONF output_bit(yyy_pin, 1) |
I want the LOW and HIGH def to configure the pin defined , on SCK_CONF and SDA_CONF is simple with output_bit function, but for SDA_STATE & SCK_STATE i want to be configure during the program , with same argument 0,1 . I think i need to made a function that acces and set the registry , right? I know i can set as input with output_float() function and the compiler choose the best option for TRIS on each pin , but now i need to do it manualy . Thanks |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Wed Sep 09, 2015 2:09 pm |
|
|
Output_float, does not "choose the best option for TRIS on each pin ". It changes only the pin you tell it.
output_float(PIN_A1); sets the TRIS bit on pin A1, to '1'.
output_drive(PIN_A1); sets the TRIS bit on pin A1 to '0'.
Exactly what you want.
If you want ot take complete control of the TRIS for the port (turn off the automatic control), then just use #use fast_io(A) (or B, C etc..
Once this is used, the compiler will completely stop controlling the TRIS on port A (or B, C etc.). It then becomes up to _you_ to set it, clear it, etc.. |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Wed Sep 09, 2015 2:16 pm |
|
|
Ttelmah wrote: |
If you want ot take complete control of the TRIS for the port (turn off the automatic control), then just use #use fast_io(A) (or B, C etc..
Once this is used, the compiler will completely stop controlling the TRIS on port A (or B, C etc.). It then becomes up to _you_ to set it, clear it, etc.. |
Curiosity:
How does fast_io work with I2C given that you have to both control the lines and release them to the slave? If you enable fast_io, do you have to gen your own I2C functions or do they still force input/output for release/control portions of the protocol? |
|
|
wangine
Joined: 07 Jul 2009 Posts: 98 Location: Curtea de Arges, Romania
|
|
Posted: Wed Sep 09, 2015 3:08 pm |
|
|
I think now will work like that
Code: |
#define SDA_STATE ctrl_DAT(x)
#define SDA_CONF output_bit(xxx_pin, 1)
#define SCK_STATE ctrl_CLK(y)
#define SCK_CONF output_bit(yyy_pin, 1) |
Code: | void ctrl_DAT(int8 state)
{
switch(state)
{
case 0:
output_drive(PIN_Bx);
break;
case 1:
output_float(PIN_Bx);
break;
default:
break;
}
}
void ctrl_CLK(int8 state)
{
switch(state)
{
case 0:
output_drive(PIN_By);
break;
case 1:
output_float(PIN_By);
break;
default:
break;
}
} |
Thanks , i didn't know output_drive() function exist in CCS because i never use TRIS in CCS, is so simply now.
Exist other better option to do that ? |
|
|
wangine
Joined: 07 Jul 2009 Posts: 98 Location: Curtea de Arges, Romania
|
|
Posted: Thu Sep 10, 2015 12:49 pm |
|
|
I want to notice, if i use output_drive() function, the compiler stuck in last state of port. Dont matter if other function set the pin as input, compiler keep that as output low or high, how has last intruction. I try fixed IO, fast IO, but same result. I close to do manually all function i need for init/start/stop/read/write and acknowledge bit on I2C. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Sep 10, 2015 7:36 pm |
|
|
What is this ?
Is it a constant like PIN_B4, or is it a variable ?
You're doing these posts where you give partial information, and there
is no easy way for us to understand your exact problem. |
|
|
wangine
Joined: 07 Jul 2009 Posts: 98 Location: Curtea de Arges, Romania
|
|
Posted: Fri Sep 11, 2015 7:21 am |
|
|
PCM programmer wrote: | What is this ?
Is it a constant like PIN_B4, or is it a variable ?
You're doing these posts where you give partial information, and there
is no easy way for us to understand your exact problem. |
I apologize , to be more clear , i try to made a driver for SHT2x series ,without use default I2C port of PIC , that will be portable for any PIC family . Exist already some samples code on sensirion website , but need to be ported on PIC-C .
Code: | //~~~~~~ declarations ~~~~~~~~~~~~~~
#define sda_pin PIN_B0
#define scl_pin PIN_B1
#define SDA ctrl_DAT(0) //SDA on I/O defines direction (input=1/output=0)
#define SDA_CONF output_bit(sda_pin, 1) //SCL level on output direction
#define SDA_READ input_state(sda_pin) // read status of input pin
#define SCL ctrl_CLK(0) //SCL on I/O defines direction (input=1/output=0)
#define SCL_CONF output_bit(scl_pin, 1) //SCL level on output direction
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// I2C level
typedef enum{
LOW = 0,
HIGH = 1,
}etI2cLevel;
// I2C acknowledge
typedef enum{
ACK = 0,
NO_ACK = 1,
}etI2cAck;
// Error codes
typedef enum{
ACK_ERROR = 0x01,
TIME_OUT_ERROR = 0x02,
CHECKSUM_ERROR = 0x04,
UNIT_ERROR = 0x08
}etError; |
Function that control SDA SCL pins status .
Code: | //~~~~~~~~~~~~~~~~~~change sda scl status ~~~~~~~~~~~~~~~~~~~~~
void ctrl_DAT(int1 state)
{
switch(state)
{
case 0:
output_drive(sda_pin);
break;
case 1:
output_float(sda_pin);
break;
default:
break;
}
}
void ctrl_CLK(int1 state)
{
switch(state)
{
case 0:
output_drive(scl_pin);
break;
case 1:
output_float(scl_pin);
break;
default:
break;
}
} |
Delay function permit to adjust SCL/SDA timing on various osc
Code: | //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void DelayMicroSeconds (int32 nbrOfUs)
{
// int32 i = 0;
for(int32 i=0; i<nbrOfUs; i++)
{
// delay_cycles(3); //8M osc
delay_us(1);
}
} |
And I2C functions
Code: | //==============================================================================
void I2c_Initialize ()
//==============================================================================
{
SDA=LOW; // Set port as output for configuration
SCL=LOW; // Set port as output for configuration
SDA_CONF=LOW; // Set SDA level as low for output mode
SCL_CONF=LOW; // Set SCL level as low for output mode
SDA=HIGH; // I2C-bus idle mode SDA released (input)
SCL=HIGH; // I2C-bus idle mode SCL released (input)
}
//==============================================================================
void I2c_StartCondition ()
//==============================================================================
{
SDA=HIGH;
SCL=HIGH;
SDA=LOW;
DelayMicroSeconds(10); // hold time start condition (t_HD;STA)
SCL=LOW;
DelayMicroSeconds(10);
}
//==============================================================================
void I2c_StopCondition ()
//==============================================================================
{
SDA=LOW;
SCL=LOW;
SCL=HIGH;
DelayMicroSeconds(10); // set-up time stop condition (t_SU;STO)
SDA=HIGH;
DelayMicroSeconds(10);
}
//==============================================================================
int8 I2c_WriteByte (int8 txByte)
//==============================================================================
{
int8 mask,error=0;
for (mask=0x80; mask>0; mask>>=1) //shift bit for masking (8 times)
{ if ((mask & txByte) == 0) SDA = LOW;//masking txByte, write bit to SDA-Line
else SDA = HIGH;
DelayMicroSeconds(1); //data set-up time (t_SU;DAT)
SCL=HIGH; //generate clock pulse on SCL
DelayMicroSeconds(5); //SCL high time (t_HIGH)
SCL=LOW;
DelayMicroSeconds(1); //data hold time(t_HD;DAT)
}
SDA=HIGH; //release SDA-line
SCL=HIGH; //clk #9 for ack
DelayMicroSeconds(1); //data set-up time (t_SU;DAT)
if(SDA_READ==HIGH) error=ACK_ERROR; //check ack from i2c slave
SCL=LOW;
DelayMicroSeconds(20); //wait time to see byte package on scope
return error; //return error code
}
//==============================================================================
int8 I2c_ReadByte (etI2cAck ack)
//==============================================================================
{
int8 mask,rxByte=0;
SDA=HIGH; //release SDA-line
for (mask=0x80; mask>0; mask>>=1) //shift bit for masking (8 times)
{ SCL=HIGH; //start clock on SCL-line
DelayMicroSeconds(1); //data set-up time (t_SU;DAT)
DelayMicroSeconds(3); //SCL high time (t_HIGH)
if (SDA_READ==1) rxByte=(rxByte | mask); //read bit
SCL=LOW;
DelayMicroSeconds(1); //data hold time(t_HD;DAT)
}
SDA=ack; //send acknowledge if necessary
DelayMicroSeconds(1); //data set-up time (t_SU;DAT)
SCL=HIGH; //clk #9 for ack
DelayMicroSeconds(5); //SCL high time (t_HIGH)
SCL=LOW;
SDA=HIGH; //release SDA-line
DelayMicroSeconds(20); //wait time to see byte package on scope
return rxByte; //return error code
} |
Like i say, if i use output_drive() function and i do some write address without ack, the controller made first pulse and after go in output_drive() function, the stat of pin as I/O will never change.
Last edited by wangine on Fri Sep 11, 2015 11:52 am; edited 1 time in total |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Fri Sep 11, 2015 8:55 am |
|
|
Code: |
SDA=HIGH; //release SDA-line
|
I may be missing something, but your comment indicates you want to release the SDA line while your code "drives" the SDA line, not permitting the slave to ack or nack. You would need to float the line at this point so the slave can choose to drive it low if it wants to.
Similar issues in other spots. |
|
|
wangine
Joined: 07 Jul 2009 Posts: 98 Location: Curtea de Arges, Romania
|
|
Posted: Fri Sep 11, 2015 11:59 am |
|
|
jeremiah wrote: | Code: |
SDA=HIGH; //release SDA-line
|
I may be missing something, but your comment indicates you want to release the SDA line while your code "drives" the SDA line, not permitting the slave to ack or nack. You would need to float the line at this point so the slave can choose to drive it low if it wants to.
Similar issues in other spots. |
Yes that will do ctrl_DAT(int1 state) function , if state is HIGH - 0 will release SDA line , is float in case 1 , state 0 is output_drive() , im so confused right now |
|
|
RLScott
Joined: 10 Jul 2007 Posts: 465
|
|
Posted: Sun Sep 13, 2015 7:17 am |
|
|
It seems that much of the confusion expressed in this thread is over what specifically the various CCS library functions, like output_float(PIN_A1), actually do. I suggest that for simple functions like this, it is best to skip the CCS library altogether and use more primitive instructions. For example, if somewhere in your project's processor-specific includes you have:
Code: | struct {
unsigned int RA0:1;
unsigned int RA1:1;
unsigned int RA2:1;
unsigned int RA3:1;
unsigned int RA4:1;
unsigned int RA5:1;
unsigned int RA6:1;
unsigned int RA7:1;
} TRISA;
#byte TRISA = 0xF92 |
Then the TRISA register can be set all at once with the C instruction:
Code: | TRISA = 0b11111101; //..(all inputs except for RA1)
|
This compiles to two machine instructions, and is as efficient as it can be. Also it is understandable. You just need to know your processor and its registers, which you really should know anyway, even when you are using the CCS library to insulate you from a first-level understanding of those registers.
Furthermore, you can declare application-specific names for the bits of PORTA and its TRIS register as in:
Code: | #define MotorStatusTrisBit TRISA.RA1
|
So now you can write:
Code: | MotorStatusTrisBit = 1; //..make RA1 go floating
MotorStatusTrisBit = 0; //..drive RA1 as an output
|
Each of these statements compile to a single bit-setting or bit-clearing machine instruction and do just what output_float(PIN_A1) and output_drive(PIN_A1) would do (set or clear just one bit and leave the rest as they were) without the need to reference the CCS library.
In many cases the CCS library presents a simpler interface to complicated functions, but not in this case. In this case the CCS library presents an interface that is no simpler than the primitive register access itself, so why bother with the CCS library here? _________________ Robert Scott
Real-Time Specialties
Embedded Systems Consulting |
|
|
wangine
Joined: 07 Jul 2009 Posts: 98 Location: Curtea de Arges, Romania
|
|
Posted: Sun Sep 13, 2015 6:00 pm |
|
|
Yes, a great answer. I don't know why i don't think of it by myself. Some years ago i has same problem with dsPIC33FJ128MC804 with FRC and PLL to bring up to 80Mhz, also with ADC function, was impossible to init with CCS function like I wish,
Code: |
void initAdc1(void)
{
AD1CON1bits.FORM = 0b00; // Data Output Format: Signed Fraction (Q15 format)// facut unsigned fost 3 pt1023=0b00
AD1CON1bits.SSRC = 2; // Sample Clock Source: GP Timer starts conversion
AD1CON1bits.ASAM = 1; // ADC Sample Control: Sampling begins immediately after conversion
AD1CON1bits.AD12B = 0; // 10-bit ADC operation
// AD1CON2bits.CSCNA = 1; // Scan Input Selections for CH0+ during Sample A bit
AD1CON2bits.CHPS = 0; // Converts CH0
AD1CON3bits.ADRC = 0; //0 // ADC Clock is derived from Systems Clock
AD1CON3bits.ADCS = 1; //63 // ADC Conversion Clock Tad=Tcy*(ADCS+1)= (1/40M)*64 = 1.6us (625Khz)
// ADC Conversion Time for 10-bit Tc=12*Tab = 19.2us
// setup_adc( ADC_TAD_MUL_4);
setup_adc_ports( VSS_VDD);
AD1CON2bits.SMPI = (NUM_CHS2SCAN-1); // 4 ADC Channel is scanned
//AD1CSSH/AD1CSSL: A/D Input Scan Selection Register
///? AD1CSSH = 0x0000;
AD1CSSLbits.CSS0=1; // Enable AN0 for channel scan
|
Just a piece of code, I was forced to modify originally dsPIC.h file with some structures that access each register, like you say, primitive functions but also very fast access. QEI module was same problem. Thanks alot, you opened my mind again. |
|
|
|
|
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
|