XC Ports and Clock Edges

Technical questions regarding the XTC tools and programming with XMOS.
User avatar
jonathan
Respected Member
Posts: 377
Joined: Thu Dec 10, 2009 6:07 pm
Contact:

XC Ports and Clock Edges

Post by jonathan »

Hello, some advice. The XC manual states (several times):
An output by the processor causes the port to drive output data on the next falling edge of its clock; the data is held by the port until another output is performed.
Now let's suppose I actually want a port that drives output data on the next rising edge of the clock instead. I've had a good look through the docs but can't find any configuration/helper function to do this... which seems very odd.

Thanks for any help/guidance. I know there are a few ways "around" this but was hoping to just be able to specify whether it's driven on a rising or falling edge.

NB The way I get around this in my current source is by actually creating another port, which is driven from the same clock but is inverted, using this to drive the output data port, whilst using the original clock for the SPI clock. This is a messy, wasteful way to solve the problem!


Image
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

Never tried it myself but, what about all the port manipulation in the xs1.h as for an example:
(Maybe you can invert the clock input , but I'm only guessing here)

void set_port_inv ( void port p )

Configures a 1-bit port to invert data which is sampled and driven on its pin.
If the port is not a 1-bit port, an exception is raised. If the port is used as the source for a clock then setting this mode has the effect of the swapping the rising and falling edges of the clock.

Parameters:
p The 1-bit port to configure.

See also:
set_port_no_inv
Probably not the most confused programmer anymore on the XCORE forum.
User avatar
jonathan
Respected Member
Posts: 377
Joined: Thu Dec 10, 2009 6:07 pm
Contact:

Post by jonathan »

Yes - I found that at first, but all this actually does is invert the clock...

Inverting the clock doesn't change the behaviour of the port clocked off it! The specification says that the port will drive data on the falling edge. So inverting the clock doesn't help - it will waits for the falling edge... this just shifts the output.

However, my current (ugly) solution does still use this function. Create a new port driven from the same source but use this function to invert it - and then using this new port to clock the data port, whilst outputting the original port as the (SPI) clock. But as I said, that's pretty damn messy and wasteful.

What we need is something like:

void configure_out_port(port p, clock c, bool initialvalue, bool edge);

To make it programmable which edge of the clock the data is driven on. I am kind of assuming that hardware can do this?
Image
User avatar
lilltroll
XCore Expert
Posts: 956
Joined: Fri Dec 11, 2009 3:53 am
Location: Sweden, Eskilstuna

Post by lilltroll »

OKi, I didn't know if the inverter was pre or post -side of the edge detect.

Know I know :)

More info to put on the wiki...

Is the driving clock (as I understand it, an external one) having a 50-50% duty cycle ?
Probably not the most confused programmer anymore on the XCORE forum.
User avatar
jonathan
Respected Member
Posts: 377
Joined: Thu Dec 10, 2009 6:07 pm
Contact:

Post by jonathan »

I am using an internally generated clock from the reference clock, and so yes, it has a 50% duty cycle.
Image
User avatar
Folknology
XCore Legend
Posts: 1274
Joined: Thu Dec 10, 2009 10:20 pm
Contact:

Post by Folknology »

In one way your solution is elegant having two pins means complimentary clocks which could help drive mixed peripherals (spi devices with mixed CPOL). but its a bit of a penalty when driving peripherals with the same CPOL modes, in those cases you just need to change CPHA which could be done on the fly in software of course with edge control. Worse still for a single peripheral that are either Mode 0 or Mode 2, both which require positive edge triggering. Another issue is can it be changed on the fly rather than just a config calls, to coincide prior to selects on different phased peripherals.

I would love to know the answers to Jonathan's question as edge selection is a common requirement for interfacing with different serial schemes.

regards
Al
User avatar
Andy
Respected Member
Posts: 279
Joined: Fri Dec 11, 2009 1:34 pm

Post by Andy »

I believe this problem is the same one that appeared here: http://xcore.com/forum/viewtopic.php?f=10&t=333

I'm not sure if the OP ever found a solution.
User avatar
jonathan
Respected Member
Posts: 377
Joined: Thu Dec 10, 2009 6:07 pm
Contact:

Post by jonathan »

Bump: anyone at XMOS confirm one way or another?

I don't mind if the answer is "no it can't do that, sorry." I just need to know!
Image
User avatar
Woody
XCore Addict
Posts: 165
Joined: Wed Feb 10, 2010 2:32 pm

Post by Woody »

I'm afraid port outputs are always updated on the falling edge of the port's clock.

If your clock source is a 1bit port, then you can use two clock blocks and have one driven by the inverted port using set_port_inv() as lilltroll suggested.

If you're generating the clock internally, you may be able to run the clock at twice your desired frequency and change the outputs on alternate -ve clock edges. Or driving the clock out on a pin and inputting it on another pin.
User avatar
jonathan
Respected Member
Posts: 377
Joined: Thu Dec 10, 2009 6:07 pm
Contact:

Post by jonathan »

Woody wrote:I'm afraid port outputs are always updated on the falling edge of the port's clock.
OK thanks. I already found solutions, just wanted to know the answer.

You might consider adding the "use another clock block" as an automatically compiled solution permitting the following helper function:

configure_out_port(port, clock, initialvalue, edge)

Unfortunately that isn't brilliant but at least hides some of the bizarreness of code that achieves the effect. De-coding what exactly is happening in a block of someone else's uncommented source code that has to use another clock block purely to select a different clocking edge (or one of your more creative solutions) would be a nightmare. For maintainability, adding this solution to the helper function above would look *much* cleaner.
Image
Post Reply