- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm a relative noob to PSOC, and am trying to identify the simplest/best (leaning strongly toward simplest 🙂 approach to implementing a counter that can count up and down. The 'Base Counter' verilog component outwardly looks like it might fit the bill (specifically, it's 'Clock and Direction' mode), but I can find no data sheet, documentation, code examples, etc for it. (I've started picking my way through the .v file for it, but it's slow going for a noob.)
Is there any type of code example for the use of this component? If someone more experienced thinks this is not the simplest/best approach to implementing a counter that can count up and/or down, I'd be open to suggestions!
I'm trying to implement a step/dir stepper driver, and would ideally like to use the counter value to keep track the motor's assumed position, as it is subsequently fed pos/neg steps by a PID process, if that helps add any clarity to what I'm trying to get to. The other side of that is that I'd like it to sort of be a 'fire and forget' type of process - w/o the need for interrupts, continually calling the stepper routine, etc - so call a 'moveToPosition(p)' and/or 'moveSteps(s)' type of function, would set the counter's compare or period value, sets the direction needed to get there, and then the hardware drives the needed number of step pulses to get to the target position, w/o the firmware having to really be involved. (I'm also open to suggestions on that type of process, if anyone has any to offer!)
Oh, I'm working with a PSOC62 on the CY8CKIT-062-WiFi-BT Pioneer Kit.
Thanks for any assistance - I'm loving the PSOC world, it's just a whole 'nuther level beyond the simpler uC's I've used in the past! 🙂
Jim
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Although I think that using Datapath should be more efficient, I tried using Verilog.
I used CY8CKIT-062-WiFi-BT.
========================
//`#start body` -- edit after this line, do not edit this line
module ud_cntr(
input rst, /* cync clear */
input clk, /* clock */
input up_ndn, /* 0: down 1: up */
input [7:0] max, /* max value */
output reg [7:0] cnt, /* count value */
output tc /* terminal count */
) ;
assign tc = (up_ndn == 1'b1) ? cnt == max : cnt == 8'd0 ;
always @(posedge clk) begin
if (rst == 1'b1)
if (up_ndn == 1'b1) /* up count */
cnt <= 8'd0 ;
else /* down count */
cnt <= max ;
else
if (up_ndn == 1'b1) /* up count */
if (cnt < max)
cnt <= cnt + 8'd1 ;
else
cnt <= 8'd0 ;
else /* down count */
if (cnt > 8'd0)
cnt <= cnt - 8'd1 ;
else
cnt <= max ;
end
endmodule
//`#end` -- edit above this line, do not edit this line
========================
To test the module, I utilized tty_utils.[ch] and func_list.[ch] from my sample code
MCU Tester, a Swiss Army Knife for PSoC (CY8CKIT-062-BLE version)
Tera Term log
Schematic
Pins
main_cm4.c
==================
#include "project.h"
#include "stdio.h"
#include "tty_utils.h"
#include "func_list.h"
int current_core = USE_CM4 ;
void do_help(void) ;
void do_step(void) ;
void do_run(void) ;
void do_up(void) ;
void do_down(void) ;
void do_max(void) ;
void do_reset(void) ;
void do_status(void) ;
void cycle_clock(void) ;
void show_values(void) ;
f_list_type main_func_list[] = {
{ "help", do_help, "show help message" },
{ "step", do_step, "advance 1 cycle" },
{ "run", do_run, "advance n cycles:<ex> run 4" },
{ "up" , do_up, "set direction to up count" },
{ "down", do_down, "set direction to down count" },
{ "max", do_max, "set max vaule" },
{ "reset", do_reset, "reset the counter" },
{ "status", do_status, "show current setup" },
{ 0, 0, 0 }
} ;
void init_hardware(void)
{
__enable_irq(); /* Enable global interrupts. */
tty_init(USE_CM4) ;
}
int main(void)
{
func_ptr func ;
init_hardware() ;
cls() ;
splash("PSoC 6 Verilog Counter Test") ;
do_help() ;
prompt("> ") ;
for(;;)
{
if (get_line()) {
func = get_func(main_func_list, str) ;
if (func) {
func() ;
} else {
print("Unknown Command: ") ;
print(str) ;
print("\r\n") ;
do_help() ;
}
prompt("> ") ;
}
}
}
void cycle_clock(void)
{
uint8_t tmp ;
tmp = Control_Reg_Read() ;
tmp = tmp ^ 0x02 ; /* clock = 0 */
Control_Reg_Write(tmp) ;
tmp = tmp | 0x02 ; /* clock = 1 */
Control_Reg_Write(tmp) ;
tmp = tmp ^ 0x02 ; /* clock = 0 */
Control_Reg_Write(tmp) ;
}
void show_values(void)
{
char buf[32] ;
snprintf(buf, 30, "%d %d\n\r", CNT_Read(), TC_Read()) ;
print(buf) ;
}
void do_help(void)
{
show_help(main_func_list) ;
}
void do_step(void)
{
cycle_clock() ;
show_values() ;
}
void do_run(void)
{
int i, n ;
sscanf(str, "%*s %d", &n) ;
for (i = 0 ; i < n ; i++ ) {
cycle_clock() ;
show_values() ;
CyDelay(10) ;
}
}
void do_up(void)
{
uint8_t tmp ;
tmp = Control_Reg_Read() ;
tmp |= 0x4 ; /* up_ndn = 1 */
Control_Reg_Write(tmp) ;
}
void do_down(void)
{
uint8_t tmp ;
tmp = Control_Reg_Read() ;
tmp ^= 0x4 ; /* up_ndn = 0 */
Control_Reg_Write(tmp) ;
}
void do_max(void)
{
int max ;
sscanf(str, "%*s %d", &max) ;
max_Write(max) ;
}
void do_reset(void)
{
uint8_t tmp ;
tmp = Control_Reg_Read() ;
tmp |= 0x01 ; /* reset = 1 */
Control_Reg_Write(tmp) ;
cycle_clock() ;
tmp ^= 0x01 ; /* reset = 0 */
Control_Reg_Write(tmp) ;
show_values() ;
}
void do_status(void)
{
uint8_t tmp, max, cnt, tc ;
tmp = Control_Reg_Read() ;
max = max_Read() ;
cnt = CNT_Read() ;
tc = TC_Read() ;
print("=== Current Status ===\n\r") ;
snprintf(str, STR_BUF_LEN, "Reset: %d\n\r", tmp & 0x01) ;
print(str) ;
snprintf(str, STR_BUF_LEN, "Clock: %d\n\r", (tmp >> 1) & 0x01) ;
print(str) ;
print("Direction: ") ;
if (tmp & 0x04) {
print("Up\n\r") ;
} else {
print("Down\n\r") ;
}
snprintf(str, STR_BUF_LEN, "Max: %d\n\r", max) ;
print(str) ;
snprintf(str, STR_BUF_LEN, "Count: %d\n\r", cnt) ;
print(str) ;
snprintf(str, STR_BUF_LEN, "Terminal Count: %d\n\r", tc) ;
print(str) ;
print("\n\r") ;
}
==================
moto
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello Jim,
You can go through the following appnote: Designing PSoC Creator™ Components With UDB Datapaths
The appnote mentions the detailed steps on creating an up/down counter using verilog. You can have a look at the project#- Up/Down Counter that comes with the project. You can edit the verilog code to customize the component as per your requirement.
The Application note is for PSoC 3, 4 and 5LP but the same steps can be followed for PSoC 6 as well when using PSoC Creator.
The appnote will also help you to understand the other ways that can also be used for creating a custom component.
Best Regards
Ekta
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
JiSt,
Before diving into Verilog, I would check if the Counter component already has the count/direction or count_up/count_dn features like PSoC5 UDB Counter has.
If not, I would try to copy/modify PSoC5 Counter component into your project, which might be not simple, as the component is quite complex.
The issue with basic counter is that reading the counter require status register, and stock component is only 8-bit wide. Going above 8-bit will require tinkering.
/odissey1
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Although I think that using Datapath should be more efficient, I tried using Verilog.
I used CY8CKIT-062-WiFi-BT.
========================
//`#start body` -- edit after this line, do not edit this line
module ud_cntr(
input rst, /* cync clear */
input clk, /* clock */
input up_ndn, /* 0: down 1: up */
input [7:0] max, /* max value */
output reg [7:0] cnt, /* count value */
output tc /* terminal count */
) ;
assign tc = (up_ndn == 1'b1) ? cnt == max : cnt == 8'd0 ;
always @(posedge clk) begin
if (rst == 1'b1)
if (up_ndn == 1'b1) /* up count */
cnt <= 8'd0 ;
else /* down count */
cnt <= max ;
else
if (up_ndn == 1'b1) /* up count */
if (cnt < max)
cnt <= cnt + 8'd1 ;
else
cnt <= 8'd0 ;
else /* down count */
if (cnt > 8'd0)
cnt <= cnt - 8'd1 ;
else
cnt <= max ;
end
endmodule
//`#end` -- edit above this line, do not edit this line
========================
To test the module, I utilized tty_utils.[ch] and func_list.[ch] from my sample code
MCU Tester, a Swiss Army Knife for PSoC (CY8CKIT-062-BLE version)
Tera Term log
Schematic
Pins
main_cm4.c
==================
#include "project.h"
#include "stdio.h"
#include "tty_utils.h"
#include "func_list.h"
int current_core = USE_CM4 ;
void do_help(void) ;
void do_step(void) ;
void do_run(void) ;
void do_up(void) ;
void do_down(void) ;
void do_max(void) ;
void do_reset(void) ;
void do_status(void) ;
void cycle_clock(void) ;
void show_values(void) ;
f_list_type main_func_list[] = {
{ "help", do_help, "show help message" },
{ "step", do_step, "advance 1 cycle" },
{ "run", do_run, "advance n cycles:<ex> run 4" },
{ "up" , do_up, "set direction to up count" },
{ "down", do_down, "set direction to down count" },
{ "max", do_max, "set max vaule" },
{ "reset", do_reset, "reset the counter" },
{ "status", do_status, "show current setup" },
{ 0, 0, 0 }
} ;
void init_hardware(void)
{
__enable_irq(); /* Enable global interrupts. */
tty_init(USE_CM4) ;
}
int main(void)
{
func_ptr func ;
init_hardware() ;
cls() ;
splash("PSoC 6 Verilog Counter Test") ;
do_help() ;
prompt("> ") ;
for(;;)
{
if (get_line()) {
func = get_func(main_func_list, str) ;
if (func) {
func() ;
} else {
print("Unknown Command: ") ;
print(str) ;
print("\r\n") ;
do_help() ;
}
prompt("> ") ;
}
}
}
void cycle_clock(void)
{
uint8_t tmp ;
tmp = Control_Reg_Read() ;
tmp = tmp ^ 0x02 ; /* clock = 0 */
Control_Reg_Write(tmp) ;
tmp = tmp | 0x02 ; /* clock = 1 */
Control_Reg_Write(tmp) ;
tmp = tmp ^ 0x02 ; /* clock = 0 */
Control_Reg_Write(tmp) ;
}
void show_values(void)
{
char buf[32] ;
snprintf(buf, 30, "%d %d\n\r", CNT_Read(), TC_Read()) ;
print(buf) ;
}
void do_help(void)
{
show_help(main_func_list) ;
}
void do_step(void)
{
cycle_clock() ;
show_values() ;
}
void do_run(void)
{
int i, n ;
sscanf(str, "%*s %d", &n) ;
for (i = 0 ; i < n ; i++ ) {
cycle_clock() ;
show_values() ;
CyDelay(10) ;
}
}
void do_up(void)
{
uint8_t tmp ;
tmp = Control_Reg_Read() ;
tmp |= 0x4 ; /* up_ndn = 1 */
Control_Reg_Write(tmp) ;
}
void do_down(void)
{
uint8_t tmp ;
tmp = Control_Reg_Read() ;
tmp ^= 0x4 ; /* up_ndn = 0 */
Control_Reg_Write(tmp) ;
}
void do_max(void)
{
int max ;
sscanf(str, "%*s %d", &max) ;
max_Write(max) ;
}
void do_reset(void)
{
uint8_t tmp ;
tmp = Control_Reg_Read() ;
tmp |= 0x01 ; /* reset = 1 */
Control_Reg_Write(tmp) ;
cycle_clock() ;
tmp ^= 0x01 ; /* reset = 0 */
Control_Reg_Write(tmp) ;
show_values() ;
}
void do_status(void)
{
uint8_t tmp, max, cnt, tc ;
tmp = Control_Reg_Read() ;
max = max_Read() ;
cnt = CNT_Read() ;
tc = TC_Read() ;
print("=== Current Status ===\n\r") ;
snprintf(str, STR_BUF_LEN, "Reset: %d\n\r", tmp & 0x01) ;
print(str) ;
snprintf(str, STR_BUF_LEN, "Clock: %d\n\r", (tmp >> 1) & 0x01) ;
print(str) ;
print("Direction: ") ;
if (tmp & 0x04) {
print("Up\n\r") ;
} else {
print("Down\n\r") ;
}
snprintf(str, STR_BUF_LEN, "Max: %d\n\r", max) ;
print(str) ;
snprintf(str, STR_BUF_LEN, "Count: %d\n\r", cnt) ;
print(str) ;
snprintf(str, STR_BUF_LEN, "Terminal Count: %d\n\r", tc) ;
print(str) ;
print("\n\r") ;
}
==================
moto