cancel
Showing results for 
Search instead for 
Did you mean: 

PSoC Creator & Designer Software

JiSt_4468101
New Contributor

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

0 Likes
Reply
1 Solution
MotooTanaka
Esteemed Contributor

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

001-TeraTerm-log.JPG

Schematic

002-schematic.JPG

Pins

003-pins.JPG

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

View solution in original post

0 Likes
Reply
3 Replies
Ekta
Moderator
Moderator

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

odissey1
Honored Contributor II

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

0 Likes
Reply
MotooTanaka
Esteemed Contributor

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

001-TeraTerm-log.JPG

Schematic

002-schematic.JPG

Pins

003-pins.JPG

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

View solution in original post

0 Likes
Reply