Defining a falling edge detection in Codesys - timer

For one of my programs I need a normally closed, timed-closing (NCTC) relay in Ladder Diagram.
I do not know of a standard method to implement such, so I'm trying to construct one myself. My current approach needs a falling-edge detection. The code of such a detector I've found in the back of a book: "IEC 61131-3:
Programming Industrial
Systems" (2nd edition, page 327). Looks like this:
FUNCTION_BLOCK F_TRIG (* falling edge *)
VAR_INPUT
CLK : BOOL;
END_VAR
VAR_OUTPUT
Q : BOOL;
END_VAR
VAR RETAIN
MEM : BOOL := 1; (* initialise edge flag *)
END_VAR
Q := NOT CLK AND NOT MEM; (* recognise falling edge *)
MEM := NOT CLK; (* reset edge flag *)
END_FUNCTION_BLOCK
Which gives me exactly 5 errors (ignoring the build failing because of those):
ERROR 4250: F_TRIG (1): Another 'ST' statement or end of POU expected
ERROR 4250: F_TRIG (4): Another 'ST' statement or end of POU expected
ERROR 4250: F_TRIG (7): Another 'ST' statement or end of POU expected
ERROR 4250: F_TRIG (10): Another 'ST' statement or end of POU expected
ERROR 4250: F_TRIG (13): Another 'ST' statement or end of POU expected
I properly configured the type of POU to be a function block and the language of the POU to be ST. I suspect my syntax is rusty, but I'm open for suggestions. Especially if I'm tackling this problem in an all wrong approach.
It looks okay to me. What's going wrong?
Running Codesys 2.3.

Delete END_FUNCTION_BLOCK
Delete RETAIN. You can retain a function block. Not a variable in a function block
Q and MEM at the bottom aren't declared as anything.
F_TRIG is already a type in codesys. Need to declare as something else
Here is an example on how it should look.
FUNCTION_BLOCK CustomTrig
VAR_INPUT
CLK : BOOL;
END_VAR
VAR_OUTPUT
Q : BOOL;
END_VAR
VAR
MEM : BOOL := 1;
END_VAR
Can you explain a little more in detail what you're trying to do? I might be able to help you develop something (or there might be something already built in to codesys)

If I understand correctly, you want the output to be:
TRUE when idle (normally closed)
FALSE during the timer
TRUE when time expires
This is the opposite of the built in TP (timed pulse) function block. Just invert the TP output 'Q'.

Related

Pointer casting problem in C with Atollic TrueSTUDIO for STM32 IDE

Working on STM32H7 in Atollic TrueSTUDIO for STM32 IDE.
Only C coding. Using FreeRTOS.
Ui08 *pointerSomething;
Ui64 localVariable;
pointerSomething=&addressOfSomething;
localVariable = *(Ui64*)(pointerSomething);
These code is generally working.
But one of my usage in a case in a thread in something like that;
thread begin //
Ui08 *pointerSomething;
Ui64 localVariable;
case 3:
pointerSomething=&addressOfSomething;
localVariable = *(Ui64*)(pointerSomething);
break;
thread end //
And I am getting a hardfault when the second sequence in these case. I mean first time in case working properly but second time in case getting hardfault exactly the line of localVariable = *(Ui64*)(pointerSomething);
thread begin //
Ui08 *pointerSomething;
Ui64 localVariable;
case 3:
pointerSomething=&addressOfSomething;
memcpy( &localVariable, pointerSomething, sizeof(localVariable) );
break;
thread end //
If I change these line as you can see above, the problem is fixing for all time of case. But my question is why this problem is occuring, casting type of line?
There is nothing to guess here.
gcc is compiling for Cortex-M7 (thumb) 64-bit pointer pun to the LDRD instruction. LDRD instruction requires aligned addresses. That is the reason why you are getting hardFaults from time to time when the address is not word aligned.
https://godbolt.org/z/o9sPvfaon
You need to make sure that the pointer references correctly aligned data. During debugging you can for example:
case 3:
if((uint32_t)pointerSomething & 3)
{
__BKPT();
}
localVariable = *(Ui64*)(pointerSomething);
and you will be able to see what is causing the HF.

VHDL average of Array through for loop

I have an Array of X Integer values in VHDL declared as a variable inside a process.
I would like to calculate the average of all Values in a for loop.
If I write it out for 3 Values manually everything works fine (tested on hardware):
entity MyEntity is
Port(
Enable : IN STD_LOGIC ;
CLK : IN STD_LOGIC;
SpeedOut : OUT INTEGER
);
end MyEntity;
Average : process
type SampleArray is Array (2 downto 0) of INTEGER;
variable SpeedSamples : SampleArray;
begin
wait until rising_edge(CLK);
if ENABLE = '1' then
SpeedOut <= ( SpeedSamples(0)+ SpeedSamples(1)+SpeedSamples(2) ) / 3;
end if;
end process Average;
If i use a for loop to do the same SpeedOut is constant 0:
entity MyEntity is
Port(
Enable : IN STD_LOGIC ;
CLK : IN STD_LOGIC;
SpeedOut : Out INTEGER
);
end MyEntity;
Average : process
type SampleArray is Array (2 downto 0) of INTEGER;
variable SpeedSamples : SampleArray;
variable tempVar : Integer;
begin
wait until rising_edge(CLK);
if ENABLE = '1' then
for i in 0 to 2 loop
tempVar := tempVar + SpeedSamples(i);
end loop;
SpeedOut <= tempVar / 3;
end if;
end process Average;
I am aware this will need a lot of resources if the Array is bigger but i think there is something fundamentally wrong with my code.
Is there a proven method of calculating a moving average in VHDL?
It's not that efficient to add up a large number of samples each clock period like that; an adder with n inputs will consume a lot of logic resource as n starts to increase.
My suggestion is to implement a memory buffer for the samples, which will have as many locations as you want samples in your rolling average. This will have one new sample written to it each clock cycle; you will also add this same sample to your total on the following clock edge.
Using dual-port memory, you can simultaneously read out the 'oldest' sample in the memory from the same location (provided you have the memory in read-before-write mode). Subtract this from your total, then perform the divide. I expect by far the most efficient divisor will be a power of two, so that your divide does not consume any logic resource. Other types of divider use relatively lots of logic.
So the design would boil down to a memory buffer, a 3-input adder, a counter for use as a pointer to the sample buffer, and a wire-shift divider. If performance was an issue, you could pipeline the add/subtract phases so that you only ever needed 2-input adders.
As for the actual coding question about creating a multi-input adder using a loop, on top of suggestions made in the comments, I would say it's really up to your synthesis tool as to whether it would be able to identify this as a multi-input adder. Have you looked in the synthesis report for any messages relating to this segment of code?

How does this sfrw(x,x_) macro work (msp430)?

I just ran into an interesting phenomenon with msp430f5529 (TI launchpad). After trying different approaches I was able to find a solution, but I don't understand what is going on here.
This code is part of a timer interrupt service routine (ISR). The special function register (SFR) TA0IV is supposed to hold the value of the interrupt number that triggered the ISR.
1 unsigned int index;
2
3 index = TA0IV; // Gives wrong value: 19874
4 index = *((volatile unsigned int *) TA0IV_); // Correct value: 4
TA0IV is defined with macros here:
5 #define sfrw_(x,x_) volatile __MSPGCC_PERIPHERAL__ unsigned int x __asm__("__" #x)
6 #define sfrw(x,x_) extern sfrw_(x,x_)
7 #define TA0IV_ 0x036E /* Timer0_A5 Interrupt Vector Word */
8 sfrw(TA0IV, TA0IV_);
What does this part of the first macro on line 5 do?
asm("__" #x)
Why is there no "x_" on the right hand side in the macro on line 5?
Last and most important question: Why does the usual typecasting on line 4 work as expected, but the one on line 3 doesn't?
BTW I use gcc-4.7.0.
Edit: More info
9 #define __MSPGCC_PERIPHERAL__ __attribute__((__d16__))
1) The # is a preprocessor "stringify" operator. You can see the impact of this using the -E compiler switch. Google "c stringify" for details.
2) Couldn't say. It isn't required that all parameters get used, and apparently whoever wrote this decided they didn't need it.
3) I'll take a shot at this one, but since I don't have all the source code or the hardware and can't experiment, I probably won't get it quite right. Maybe close enough for what you need though.
The first thing to understand is what the asm bit is doing. Normally (ok, sometimes) when you declare a variable (foo), the compiler assigns its own 'internal' name to the variable (ie _foo). However, when interfacing with asm modules (or other languages), sometimes you need to be able to specify the exact name to use, not allowing the compiler to mangle it in any fashion. That's what this asm is doing (see Asm Labels). So when you brush aside all the #define nonsense, what you've got is:
extern volatile __MSPGCC_PERIPHERAL__ unsigned int TA0IV __asm__("__TA0IV");
Since the definition you have posted is "extern," presumably somewhere (not shown), there's a symbol named __TA0IV that's getting defined. And since accessing it isn't working right, it appears that it is getting MIS-defined.
With the caveat that I HAVEN'T TRIED THIS, I would find this to be somewhat more readable:
#define TA0IV_ 0x036E
inline int ReadInterruptNumber()
{
int retval;
asm volatile("movl (%c1), %0": "=rm" (retval) : "i" (TA0IV_));
return retval;
}
FWIW.

Weird signal behaviour (clock-dependant signal changing with no clock present)

Im working on a NCO (still) and I got problems with adress select block - my teacher wants the samples in ROM block (done that already) but the adressing thingie doesnt seem to work. What I need is a modulo 200 accumulator with variable step... I adopted this code from a sample where somebody used i as counter to pick a value from an array of samples, BUT I need to simply copy i to the output port.
Something with PWM wasnt working, it skipped not ten but ~80 samples, so I decided to check the adressing - Ive been mighty surprised when I noticed that adress changes INDEPENDENTLY from the clock signal. ( http://i.imgur.com/XL9l8mj.jpg )
Heres the code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL; --try to use this library as much as possible.
entity adress_select_200 is
port (clk :in std_logic;
step :in integer range 0 to 200;
adress : out integer range 0 to 199
);
end adress_select_200;
architecture Behavioral of adress_select_200 is
signal i : integer range 0 to 399:=0;
begin
process(clk)
begin
--to check the rising edge of the clock signal
if(rising_edge(clk)) then
adress <= i;
i <= i+step;
if ((i + step) > 199) then
i <= (i + step) - 200;
else
i <= i + step;
end if;
end if;
end process;
end Behavioral;
Im not so great with VHDL, but I suppose the whole loop should ONLY execute on clk rising edge, right? Meanwhile its doing that weird sh... in the middle of the cycle, no idea why.
How do I stop that from happening?

Defining an array in verilog down to a nonzero constant

I have the following sub-module:
module test
(
input [LENGTH : 1] array;
);
...
endmodule
And I'm calling it from a top module as follows:
...
wire [LENGTH-1 : 0] array_top;
test test_i
(
.array (array_top);
);
...
Assume LENGTH is the same in both modules.
How will array_top map to array, given array_top goes down to zero but array goes to down 1?
Why would anyone define an array down to 1 and not down to 0?
What will happen to array[0]?
Thanks,
Your questions can be answered with a small testbench:
module tb;
reg [3:0] atop;
initial begin
$monitor("array_top=%b, array=%b", array_top, test_i.array);
#1 atop = 4'b0000;
#1 atop = 4'b0001;
#1 atop = 4'b0010;
#1 atop = 4'b0100;
end
wire [3:0] array_top = atop;
test test_i (.array (array_top));
endmodule
module test (input [4:1] array);
endmodule
Output:
array_top=xxxx, array=xxxx
array_top=0000, array=0000
array_top=0001, array=0001
array_top=0010, array=0010
array_top=0100, array=0100
From your connection: array[1] = array_top[0], etc.
Sometimes people want to omit connecting a signal's LSB, like an address for a memory, because the LSB has no effect.
There is no array[0] signal.
When connecting ports, Verilog only cares that arrays have the same size (called an equivalent type in SystemVerilog) It does not care about the starting index value, or whether it increases or decreases. It will start by connecting the right range (LSB) of each signal. In your case array_top[0] connects to array[1]. If the sizes do not match you may get an error or warning, depending on the tool and its settings. Then the connection will either be padded or truncated after hitting the left range (MSB).

Resources