[Solved] STC8 (8051): PWM output stuck floating - Page 1
Forum section: electronics / general

author: Whales
author_rank: Super Contributor
timestamp: December 24, 2023, 05:40:16 am
content: I am trying to use PWM6 (fed by the counter PWMB) to generate a simple PWM waveform and output it on P5.4.- P5.4 looks like it's stuck floating. It doesn't do anything.- PWMB's internal counter is definitely counting, I can see its values printed over the UART.Things I've tried:- If I remove the PWMB_ENO line then P5.4 works like a normal output (strong push/pull that I can control by setting its bit in P5).- P5.4 works fine as an MCLK0 output (beautiful high-freq square waves)- Reading someone's HAL for this family and following their exact order & pattern of reg writes (they used a descending counter + different PWM comparison mode, but still P5.4 stayed floating at around 2.7V)- Checking to make sure EAXFR_MAP & UNMAP are working as expected (I can't read PWMB_CNTR in the UART printing code if they're omitted)Chip: STC8H1K08(datasheet link). Pin 7 is "MCLK0/RST/PWM6_2/P5.4".Any ideas?Code:void main(){// Serial comms: UART1 T2SCON = 0x50; // 8 bit variable baudrate (no parity)AUXR |= 0b00000001; // clock UART from T2AUXR |= 0b00000100; // T2 in 1T modeAUXR |= 0b00010000; // T2 runT2L = UART1_TIMER_PRELOAD % 256;T2H = UART1_TIMER_PRELOAD>>8;ES = 1; // UART1 interrupt enable// Clock display brightnessPWM: P5.4 PWMB PWM6EAXFR_MAP;RSTCFG = 0b01000000; // P5.4: Make it a normal IO pin (disable chip reset functionality)P5M1 &= 0b11101111; P5M0 |= 0b00010000; // P5.4: strong push-pullPWMB_CCER1 = 0; // PWM6: Disable (required before writing to CCMR2)PWMB_CCMR2 = 0b01101000; // PWM6: PWM mode 1 and enable preload of PWMB_CCR6 (smoother PWM level changes)PWMB_CCER1 = 0b00010000; // PWM6: EnablePWMB_ENO = 0b00000100; // PWM6: Enable outputPWMB_PS = 0b00000100; // PWM6: Send to pin P5.4PWMB_PSCR = 1; // PWMB: Clock at 1/(X+1) of system clockPWMB_CCR6 = 1000; // PWMB: ratio (out of 65536)PWMB_CR1 |= 0b00000001; // PWMB: enablePWMB_BKR = 0x10000000; // PWMB: enable (disable brake) <-- might not be needed as brake not enabled?EAXFR_UNMAP;EA = 1; // global interrupt enablewhile(1){EAXFR_MAP;uint16_t curtime = ((uint16_t)PWMB_CNTRH << 8) | PWMB_CNTRL;EAXFR_UNMAP;uart1_writeStr("Current PWMB_CNTR value: ");uart1_writeHex16(curtime);uart1_write('\r');uart1_write('\n');}}

author: amyk
author_rank: Super Contributor
timestamp: December 24, 2023, 06:03:48 am
content: What's P_SW1 set to? Bits 3:2 there may map the SPI peripheral to P5.4.

author: IOsetting
author_rank: Regular Contributor
timestamp: December 24, 2023, 04:47:13 pm
content: I just tried with the code below. This can output PWM on P5.4.Code:/*** Demo: P5.4 pwm with duty cycle changed by timer2 interrupt** P5.4 -> 1k Ω resistor -> LED1+* GND -> LED1-** Note: PWM6 = PWMB_PWM2*/#include "fw_hal.h"__BIT dir = SET;uint8_t dc = 0;INTERRUPT(Timer2_Routine, EXTI_VectTimer2){PWMB_PWM2_SetCaptureCompareValue(dc);UART1_TxHex(dc);UART1_TxString("\r\n");if (dir){dc++;if (dc == 0xFF) dir = !dir;}else{dc--;if (dc == 0) dir = !dir;}}void main(void){SYS_SetClock();// UART1, baud 115200, baud source Timer1, 1T modeUART1_Config8bitUart(UART1_BaudSource_Timer1, HAL_State_ON, 115200);// Set GPIO pins output modeGPIO_P5_SetMode(GPIO_Pin_4, GPIO_Mode_Output_PP);// Turn off PWMB.2 before change its modePWMB_PWM2_SetPortState(HAL_State_OFF);// Set PWMB.2 port direction outputPWMB_PWM2_SetPortDirection(PWMB_PortDirOut);// Set PWMB.2 output low voltage when counter is less than target valuePWMB_PWM2_ConfigOutputMode(PWM_OutputMode_PWM_LowIfLess);// Enable comparison value preload to make duty cycle changing smoothPWMB_PWM2_SetComparePreload(HAL_State_ON);// Turn on PWMB.2PWMB_PWM2_SetPortState(HAL_State_ON);// Set highest PWM clockPWMB_SetPrescaler(0);// PWM width = Period + 1 (side alignment), or AutoReloadPeriod * 2 (center alignment)PWMB_SetPeriod(0xFF);// Counter direction, down:from [PWMA_ARRH,PWMA_ARRL] to 0PWMB_SetCounterDirection(PWM_CounterDirection_Down);// Enable preload on reload-periodPWMB_SetAutoReloadPreload(HAL_State_ON);// Enable output on PWMB.2PWMB_SetPinOutputState(PWM_Pin_2, HAL_State_ON);// Set PWMB.2 alternative ports to P5.4PWMB_PWM2_SetPort(PWMB_PWM6_AlterPort_P54);// Enable overall outputPWMB_SetOverallState(HAL_State_ON);// Start counterPWMB_SetCounterState(HAL_State_ON);// 1T mode, prescaler:255+1, frequency: 100TIM_Timer2_Config(HAL_State_ON, 0xFF, 100);// Timer2 interrupt: ONEXTI_Timer2_SetIntState(HAL_State_ON);EXTI_Global_SetIntState(HAL_State_ON);TIM_Timer2_SetRunState(HAL_State_ON);while(1);}Compiled withhttps://github.com/IOsetting/FwLib_STC8MakefileCode:MCU ?= STC8H1K08MCU_IRAM ?= 256# 1024, 2048, 3072, 4096, 8192MCU_XRAM ?= 1024# 8192, 16384, 32768, 65536MCU_CODE_SIZE ?= 8192##### Project #####PROJECT ?= app# The path for generated filesBUILD_DIR = buildTOOCHAIN_PREFIX ?= /opt/sdcc/sdcc-4.1.0/bin/# C source foldersUSER_CDIRS := user# C source single filesUSER_CFILES :=USER_INCLUDES := userLIB_FLAGS := __CONF_FOSC=36864000UL \__CONF_MCU_MODEL=MCU_MODEL_STC8H1K08 \__CONF_CLKDIV=0x00 \__CONF_IRCBAND=0x01 \__CONF_VRTRIM=0x1F \__CONF_IRTRIM=0xB5 \__CONF_LIRTRIM=0x00include ./rules.mkrules.mkCode:ARCH_FLAGS := -mmcs51 --model-large

author: Whales
author_rank: Super Contributor
timestamp: January 07, 2024, 07:48:15 am
content: Sorry for the late reply. Got a bad flu over Xmas and new year :|IOsetting:thankyou for your code, I'm successfully seeing the pin sweep a range of PWM ratios. I'll pick through the assembly and compare it with what I'm doing to see if there is something obviously different.I didn't end up using your Makefile (what version of make is it?) but putting all of the dep .h and .c files in the same directory and using sdcc directly got me a working ihx/hexamyk: I'll have a look, thankyou.

author: IOsetting
author_rank: Regular Contributor
timestamp: January 07, 2024, 01:38:14 pm
content: Quote from: Whales on January 07, 2024, 07:48:15 amSorry to hear that, this year's cold season is really bad, many people here have a bad flu too.I just noticed the "include ./rules.mk" is missing at the end of Makefile, adding that should make the Makefile work. I am using make 4.2.1Code:$ make --versionGNU Make 4.2.1Built for x86_64-pc-linux-gnuCopyright (C) 1988-2016 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law.

author: Whales
author_rank: Super Contributor
timestamp: January 08, 2024, 05:50:56 am
content: I found the error and it's not what I expected in the slightest. It has taken many hours to track down.I bisected the problem by replacing lines of your code with my code (they're mostly compatible). The issue exists in these two lines:PWMB_CR1 |= 0b00000001; // PWMB: enablePWMB_BKR = 0x10000000; // PWMB: enable (disable brake) <-- might not be needed as brake not enabled?Can you spot the error? I'll give a hint: it's not the fault of the micro.PWMB_CR1 |= 0b00000001; // PWMB: enablePWMB_BKR = 0x10000000; // PWMB: enable (disable brake) <-- might not be needed as brake not enabled?Changing that constant to format 0b instead of 0x magically fixes everything. My pin is now wiggling.It looks like SDCC doesn't complain when you try to write a large constant somewhere too small. In my header file PWMB_BKR is defined as:Code:#define PWMB_BKR (*(unsigned char volatile __xdata *)0xfefd)The SDCC manualdoesn't seem to list any flags to enable more warnings (like -Wall, which it rejects). I might try contacting the project and asking, but for now I'll have to replace my font with something that draws pulsating coloured beacons for the ligatures 0b and 0xThankyou IOsetting and amyk for your help, muchly appreciated.

author: IOsetting
author_rank: Regular Contributor
timestamp: January 09, 2024, 11:06:27 am
content: Who would notice thatPWMB_BKR is an unsigned char so it would be better if SDCC can raise a warning on this.