cheap dout's

Hello,

it must have been covered in the past, but i did not found anything about it.

is there a “hack” or a simple way, using c, to have few digital outputs without using a “dout module” (74HC595), in the same way we can use analog inputs (J5) as digital ones with pull up resitors.

( i now talking about J14, because i’m looking for more than one output )

I want to find the cheapest way to build sync24 outputs (we need 2 lines : clock and start)

-> http://www.midibox.org/dokuwiki/mb_sync24

Thanks !!! =)

Am i unclear, or is this “impossible”  ???

Do you mean something like demonstrated in this example: http://www.ucapps.de/mios_c_pic_pin.html

Best Regards, Thorsten.

Well, yes, probably :stuck_out_tongue:

i dont understand the example very well yet, but i guess that’s what i’m looking for.

So, Port B is the LCD data bus right ?

I can send a byte to PORTB and “read” it thanks to RB0 to RB7 ?

::slight_smile:

thank you !

So, Port B is the LCD data bus right ?

can send a byte to PORTB and “read” it thanks to RB0 to RB7 ?

You can use PortB as input when the appr. TRISB flags are set (Tristate driver - means: pin is not driving)

However, the best choice for output pins which are not used by any other resources are RC0, RC1 and RC3.

The best choice for an input pin which is not used by any other resource is RC2 (it already has an pull-up, which is perfect to prevent random values if the pin is open)

By using these pins, you don’t need to modify the TRISx configuration, just use (for example)

   PORTCbits.RC0 = 1;

to set the pin to 5V, and

   PORTCbits.RC0 = 0;

to set the pin to 0V

Same for RC1:

   PORTCbits.RC1 = 1; // 5V

   PORTCbits.RC1 = 0; // 0V

And don’t touch anything related to the LCD Port B

Hope that this answers your question?

Or do you need even more input/output pins? There are special solutions for J5 and LCD port, but they require additional configuration… and you need to warn the end-users to disconnect the LCD, or disconnect pots (of J5 used as output) to prevent short-circuits.

Best Regards, Thorsten.

Thank you Thorsten, yes, it helps a lot, but i would like to get… 8 outputs :stuck_out_tongue:

so i guess the only solution is j5 or lcd portB ! (i prefer j5)

please can you tell me where to get some informations about those special solutions ?

thanks =)

edit :


ok, i should use my brain more often… here it is http://ucapps.de/mios/j5_dout_v1_3c.zip

unfortunately, this is ASM, and i did not find any conversion to C

(i have zero ASM knowledge)  :-[

Can someone help me to turn this code into plain C ?

Once the SVN server is up&running, a modular structure will be available where code modules can be easily shared between projects.

So - once it is available, I will program a relocatable j5_dout module for you, that should be easily integratable.

Best Regards, Thorsten.

P.S.: so long the module is not available, you can control J5 outputs the following way from C:

Add

  ADCON1 = 0x07;

  TRISA &= 0xd0;

  TRISE &= 0xf8;

to the Init() hook

Now you can toggle the pins with

PORTAbits.RA0 = …

PORTAbits.RA1 = …

PORTAbits.RA2 = …

PORTAbits.RA3 = …

PORTAbits.RA5 = …  // no typo! RA4 is allocated by IIC

PORTEbits.RE0 = …

PORTEbits.RE1 = …

PORTEbits.RE2 = …

Please let me know if it works (it’s untested)

Best Regards, Thorsten.

a modular structure will be available where code modules can be easily shared between projects.

So - once it is available, I will program a relocatable j5_dout module for you, that should be easily integratable.

  :o

Wooow !!! I love you Thorsten  ;D

Thanks sooooo much, i test this this evening and revert as soon as it’s done.

I think this is well and truly under control now but… http://www.midibox.org/dokuwiki/mios_pin_list will show you a list of pins and their usage so you can tell if you can use a pin depending on your hardware…

Please let me know if it works (it’s untested)

It works !

Here is what i did : 

void J5_DOUT_Set(unsigned char oct){
  char b0 = oct;
  char b1 = oct >> 1;
  char b2 = oct >> 2;
  char b3 = oct >> 3;
  char b4 = oct >> 4;
  char b5 = oct >> 5;
  char b6 = oct >> 6;
  char b7 = oct >> 7;
  PORTAbits.RA0 = b0 & 0x01;
  PORTAbits.RA1 = b1 & 0x01;
  PORTAbits.RA2 = b2 & 0x01;
  PORTAbits.RA3 = b3 & 0x01;
  PORTAbits.RA5 = b4 & 0x01;
  PORTEbits.RE0 = b5 & 0x01;
  PORTEbits.RE1 = b6 & 0x01;
  PORTEbits.RE2 = b7 & 0x01;
}

it works, but please tell me what you think of the code !

(i guess it can be done in a better way)

No major changes just a little shorter:

void J5_DOUT_Set(unsigned char oct){
  PORTAbits.RA0 = oct & 0x01;
  PORTAbits.RA1 = (oct >> 1) & 0x01;
  PORTAbits.RA2 = (oct >> 2) & 0x01;
  PORTAbits.RA3 = (oct >> 3)  & 0x01;
  PORTAbits.RA5 = (oct >> 4)  & 0x01;
  PORTEbits.RE0 = (oct >> 5)  & 0x01;
  PORTEbits.RE1 = (oct >> 6)  & 0x01;
  PORTEbits.RE2 = (oct >> 7)  & 0x01;
}
[/code]

try this (off the top of my head):

void J5_DOUT_Set(unsigned char oct)
{
  PORTAbits.RA0 = (oct & 0x01) && 1;  
  PORTAbits.RA1 = (oct & 0x02) && 1; 
  PORTAbits.RA2 = (oct & 0x04) && 1;
  PORTAbits.RA3 = (oct & 0x08) && 1;
  PORTAbits.RA5 = (oct & 0x10) && 1;
  PORTEbits.RE0 = (oct & 0x20) && 1;
  PORTEbits.RE1 = (oct & 0x40) && 1;
  PORTEbits.RE2 = (oct & 0x80) && 1;
}

!= 0 might be better than && 1, have to look at asm output…

(maybe could even do without the && 1 at all)

Thank you guys !

I knew there was an elegant way to do that :slight_smile:

Semi-untested and possibly controversial:

__asm
MOVF	_PORTA, _WREG
IORLW	0x1F
MOVF	_WREG, _PORTA
MOVF _oct, _WREG
IORLW 0xE0
ANDWF _PORTA, 1

MOVF	_PORTE, _WREG
IORLW	0x07
MOVF	_WREG, _PORTE
MOVF _oct, _WREG
RRNCF _WREG, 5
IORLW 0xF8
ANDWF	_PORTE, 1
__endasm;
[/code]


Or sth. pretty close to what ptitjes suggested in the chat:
[code]  
 PORTA = (oct & 0x1F) | (PORTA & 0xE0);  
 PORTE = ((oct \>\> 5) & 0x07) | (PORTE & 0xF8);

See also:

http://svnmios.midibox.org/trunk/apps/sequencers/midibox_seq_v3/src/j5_dout.inc

(which can be optimized, yes… it’s quite old. And it’s better to use PROD[LH] as temporary registers than MIOS_PARAMETER[12])

The official j5_dout module will get a C wrapper, similar to this module: http://svnmios.midibox.org/trunk/modules/iic_midi

So that it can be used by asm and C programs…

Best Regards, Thorsten.

Or sth. pretty close to what ptitjes suggested in the chat:

In fact this was :

PORTA = (PORTA & 0xF0) | (oct & 0x0F);
if (oct & 0x10) { PORTAbits.RA5 = 1; } else { PORTAbits.RA5 = 0; }
PORTE = (PORTE & 0x1F) | ((oct & 0xE0) >> 5);

which is the most efficient C code I found by looking to the generated asm…

In fact this was :

PORTA = (PORTA & 0xF0) | (oct & 0x0F);
if (oct & 0x10) { PORTAbits.RA5 = 1; } else { PORTAbits.RA5 = 0; }
PORTE = (PORTE & 0x1F) | ((oct & 0xE0) >> 5);
[/code]

which is the most efficient C code I found by looking to the generated asm…

There are two issues, and two improvements to make it a bit faster (in C, the assembly variant beats it anyhow ;))

a) it isn’t guaranteed, that reading PORTA returns the same values which have been written into PORTA, because the “read view” of this register returns the current values of the input stage, while writing into PORTA is directed to the output stage.

Simple example: you are using RA4 as open drain pin, and you are setting it 1 to deactivate the output driver. But you could read 0, e.g. if an external device drives the dominant (=0) value.

Accordingly, with PORTA = (PORTA & 0xf0) … you would accidently activate the output driver of RA4 in such a scenario!

Thats the reason, why the LATx registers have been introduced in the PIC18F family - it gives you direct read and write access to the output register. And thats also the reason, why I prefer to access LATx registers in my code

(btw.: there is also a pipeline issue with PORTx registers, e.g. sequential read-modify-write operations (bsf/bcf/btg) can fail if they are done without at least one instruction between the accesses, because the second RMW access would read the previous value of the *input* register - which wasn’t already updated by the new output  value at this time)

b) wrong mask is applied on PORTE (0x1f instead of 0xf8)

c) “(oct & 0xe0) >> 5)” - the AND mask is probably redundant, if C clears the carry flag before doing the shift operation, and masks the value after the swap operation (I would expect this)

d) you could also write: “LATA = (LATA & 0xd0) | (oct & 0x0F) | ((oct & 0x10) ? 0x20 : 0x00);”

Best Regards, Thorsten.

There are two issues, and two improvements to make it a bit faster (in C, the assembly variant beats it anyhow ;))

a) it isn’t guaranteed, that reading PORTA returns the same values which have been written into PORTA, because the “read view” of this register returns the current values of the input stage, while writing into PORTA is directed to the output stage.

Simple example: you are using RA4 as open drain pin, and you are setting it 1 to deactivate the output driver. But you could read 0, e.g. if an external device drives the dominant (=0) value.

Accordingly, with PORTA = (PORTA & 0xf0) … you would accidently activate the output driver of RA4 in such a scenario!

Thats the reason, why the LATx registers have been introduced in the PIC18F family - it gives you direct read and write access to the output register. And thats also the reason, why I prefer to access LATx registers in my code

I read that in the I/O pin section of the datasheet but not understood it at first. I’m not so used to read the simplified diagrams. That’s ok now I think.

(btw.: there is also a pipeline issue with PORTx registers, e.g. sequential read-modify-write operations (bsf/bcf/btg) can fail if they are done without at least one instruction between the accesses, because the second RMW access would read the previous value of the *input* register - which wasn’t already updated by the new output  value at this time)

Did not know the PIC had a pipelined architecture ! I hope sdcc takes care of this when he optimizes code…

b) wrong mask is applied on PORTE (0x1f instead of 0xf8)

Oups!

c) “(oct & 0xe0) >> 5)” - the AND mask is probably redundant, if C clears the carry flag before doing the shift operation, and masks the value after the swap operation (I would expect this)

Yeah! I did not even think of it :slight_smile:

d) you could also write: “LATA = (LATA & 0xd0) | (oct & 0x0F) | ((oct & 0x10) ? 0x20 : 0x00);”

Well. I looked at the generated code for ternary (?:slight_smile: and it used intermediate viariables and the generated code is not optimized then simple if then set else set…

Best regards, Didier.