This is related to the TCPWM component which is the same throughout all PSoC4 family members. Seems to be better to issue a Stop() and Enable API call.
Using Stop() is not good for me. I need the PWM counter always running , because I use its TC output for synchronization with other components.
There are a couple of options to make the PWM output low, while keeping the counter running.
Use the HSIOM_PORT_SELx register to disconnect the pin from the TCPWM output. Details of this register can be found in the High-Speed I/O Matrix section in the architecture TRM.
In the TCPWM component, enable the "Stop" event and set the Mode to "Level". Set the stop signal event to "Don't stop on kill".
Connect a control register to the stop signal input. Write a 1 to the control register to make the line and line_n output to go low while the counter keeps running and you keep getting the terminal count events.
Thank you for your suggestions.
I can't use the control register option, because my project is restricted to software only (no UDB usage).
The HSIOM_PORT_SELx doesn't seem to work. It disconnects the PWM from the output, but it doesn't seem to reconnect it back, when I try to restore the register setting.
In the TRM it's written that the pin's OE can be controlled by firmware, but I can't find how to do this. Maybe it's another option to implement my project.
It seems that the PWM doesn't reconnect because I use Pin_1_Write(0) in initialization.
I added this line because without it the output goes high when disconnecting the PWM using the HSIOM_PORT_SELx register, and I need it to go low.
Need help with this...
(BTW, when I go back to using PWM normally, without HSIOM_PORT_SELx, it seems that Pin_1_Write(0) in initialization somehow disconnects the PWM from the pin - the output is constantly low. But using Pin_1_Write(1) doesn't make the output go constantly high... Am I missing something here...?)
Output is controlled from DSI, but OE is firmware controlled
How the firmware controls the OE? I can't find it...!
You need to worry about OE only if you have enabled OE in the pin. If you have not enabled OE in the pin (the pin component in the schematics does not have the OE signal), all you need to do is write to HSIOM_PORT_SELx register to make it either a GPIO, or connect to the TCPWM signal.
For example, if you want to connect P1_0 to TCPWM output, first configure the pin to strong drive and write a 0. This is a one time configuration.
// Configure P1_0 to Strong drive and set it to LOW
CY_SYS_PINS_SET_DRIVE_MODE(CYREG_GPIO_PRT1_PC, 0, CY_SYS_PINS_DM_STRONG);
To disconnect the PWM from P1_0, write to the HSIOM_PORT_SEL1 register.
/* Disconnect P1 from TCPWM#2 output and make it a GPIO */
TempVal = CY_GET_REG32(CYREG_HSIOM_PORT_SEL1);
TempVal &= ~0x0000000F; // Clear Bit#0 to Bit#3 to configure P1 as GPIO
To connect the PWM to P1_0, write to the HSIOM_PORT_SEL1 register
/* Connect P1 to TCPWM#2 */
TempVal = CY_GET_REG32(CYREG_HSIOM_PORT_SEL1);
TempVal &= ~0x0000000F;
TempVal |= 0x00000008;
Note: I have used direct numbers in the above code. You can find various macros in cydevice_trm.h file for bit field values (CYVAL_HSIOM_IO0_SEL_ACT_0, CYFLD_HSIOM_IO1_SEL__OFFSET etc.), which you can use for a cleaner coding.
If I enable the OE pin, PSOC Creator instructs me to connect it somewhere. Where can I connect it in order to have a firmware control over it (without using Control Register)?
Your suggestion doesn't work for me.
My TCPWM is constrained to TCPWM0, by means of directive F(TCPWM,0) in DWR (this is a fix your support team gave me for a problem I had), and the output pin is 6. The correct value for CYREG_HSIOM_PORT_SEL1 register is 3 (this is what I saw while debugging). It seems that these constraints affect the behavior. Clearing the pin somehow overrides TCPWM connection to it, and the output stays constantly low even after restoring CYREG_HSIOM_PORT_SEL1 value to TCPWM connection (which is 3 in my case). If I delete the directive, it works fine.
Actually, you do not need the OE signal at all. Just connecting and disconnecting using HSIOM register should work.
I did a project to check this concept (project is attached).
In this project, I have placed the PWM in TCPWM0 using the directive and have connected the PWM output to P2. In main.c, I am swtiching P2 between a GPIO and TCPWM every 100ms, and I can see the output switching (picture below).
As I do not have a board with 4200M device, I checked this concept with a 4200. I am sure this will work with 4200M as well. Can you have a look at the project and check if this is what you are doing? You could also change the device in this project for your target device and check if it works.
Which is the exact part number that you use in the 4200M series?
You are missing a point here...
The reason that your implementation works is because pin P2 is dedicated to TCPWM0.
Try moving the pin to P2 and changing the code accordingly. It won't work (I've tested it on CY8CKIT-043), because this pin is dedicated to TCPWM5. Even if you change the pin setting in CYREG_HSIOM_PORT_SEL2 to 3 (which is what happens when you connect PWM output to a non-TCPWM-dedicated pin - it is routed using the DSI, so the pin is configured as 3 in CYREG_HSIOM_PORT_SELx).
Then change the directive to TCPWM5 - and it will work with P2.
Sincere apologies. I had indeed missed the point about the TCPWM connected to a non-dedicated GPIO pin through the DSI logic.
I tested the project by routing the TCPWM signal to a non-dedicated pin, I could reproduce your issue. Writing 0 to the pin using Pin_Write function results in the pin not getting connected to the PWM, and if Pin_Write function is not used, the output is HIGH which is the default state.
How about this? Instead of writing a 0 to the pin and disconnecting it from TCPWM using the HSIOM_PORT_SELx register, just switch the drive mode of the pin between HighZ and Strong.
I tested this method and it works. You will need an external pull down resistor on the pin to keep the pin low when it becomes HighZ.
The other option is to enable OE signal for the pin and find out how to control this in firmware.
In the architecture TRM, in the UDB chapter, under Port Adapter Block section, there are details of how the OE signal can be controlled using some registers.
For each port, there are 4 OE signals coming from the DSI. Each of these OE signals can be configured to be transparent, single sync, logic high or logic low using the UDB_PAx_CFG14 register.
Each of the port pins can connect to one of these OE signals. This is configured using the UDB_PAx_CFG12 and UDB_PAx_CFG13 registers.
However, I did some debugging and could not find these registers controlling the OE signal. This may need some more digging into the TRM.
I've tried your SetDriveMode() suggestion on CY8CKIT-043 and it works.
What's funny is that PWM_OUT_Write(0) overrides this behavior (do you know why?) , so I had to delete it from the code.
Actually, I would prefer to control the output without using OE, because I want the output to always be Strong Drive.
Using CYREG_HSIOM_PORT_SELx seems like a good idea, if only Pin_Write() wouldn't override it...
Is this possible somehow?
I've implemented your Control Register suggestion in my project, just on a trial basis, and it seems that this way it works much smoother than with using Drive Mode. But as I've mentioned, I can't use UDBs in this project. Is there a way to implement this (using the Stop signal) with firmware only?
Found a solution for this. The Stop signal state for the TCPWM can be controlled without any UDB or DSI by writing to the CNT_STOP_SEL bits in the TCPWM_CNTx_TR_CTRL0 register.
In the schematic, enable the stop signal, set the trigger mode to "Level", set stop signal event to "Dont stop on kill", and connect a logic 1 to the stop input. This will start the PWM with output low.
Write a 0 to the CNT_STOP_SEL bits to make the stop input logic 0. And the PWM output will be available on the pin.
I used the below code in my test project and am able to stop the PWM output and start it without having to change the pin drive mode or pin state.
/* Set the CNT_STOP_SEL bits to 0 which selects a logic 0 as Stop input */
TempVal = CY_GET_REG32(CYREG_TCPWM_CNT0_TR_CTRL0);
TempVal &= ~0x0000F000;
/* Set the CNT_STOP_SEL bits to 1 which selects a logic 1 as Stop input */
TempVal |= 0x00001000;
I did not check if the TC output keep occuring (I am sure that should work fine). Please try this and let me know if this works for you.