Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions examples/0timerint/timer.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "main.h"
#include "defines.h"
#include "romfunctions.h"
#include "rtc.h"
#include "typeaux.h"
#include "uart.h"
#include "utils/uartutils.h"
Expand Down Expand Up @@ -242,6 +243,29 @@ static void _uart_cycle(uint64_t u64tckNow) {
case 'i':
uart_printf(&gsUART0, "Ccompare%u\r\n", gsMeasParam.eCcompare);
break;
case 'z': // cycle through CPU_CPUPERIOD_SEL values
Reg rCpuPeriod = dport_regs()->CPU_PER_CONF & 3;
++rCpuPeriod;
rCpuPeriod &= 3;
dport_regs()->CPU_PER_CONF = rCpuPeriod;
uart_printf(&gsUART0, "CPU_CPUPERIOD_SEL = %u\r\n", rCpuPeriod);
break;
case 'x': // cycle through clock sources
Reg rClkConf = gsRTC.CLK_CONF;
uart_printf(&gsUART0, "CLK_CONF = %08x\r\n", rClkConf);
uint32_t u32ClockSource = (rClkConf >> 27) & 3;
do {
++u32ClockSource;
u32ClockSource &= 3;
} while (u32ClockSource == 0 || u32ClockSource == 2);
rClkConf &= ~(3 << 27);
rClkConf |= (u32ClockSource << 27);
// this will not work here:
// switching to any CLK SRC other than PLL will also cause change in APB frequency
// thus change in UART0 speed
// gsRTC.CLK_CONF = rClkConf;
uart_printf(&gsUART0, "RTC_CNTL_SOC_CLK_SEL = %u (%08x)\r\n", u32ClockSource, rClkConf);
break;

// Alarm value modification
case '>':
Expand Down Expand Up @@ -312,7 +336,12 @@ static void _print_resultline(uint32_t u32Idx, const Result * psResult) {

// -------------- Interface functions --------------

// RTC_CNTL_SOC_CLK_SEL SoC clock selection. 0: XTAL, 1: PLL, 2: CK8M, 3: APLL. (R/W)
#define RTC_CNTL_SOC_CLK_SEL 1

void prog_init_pro_pre() {
gsRTC.CLK_CONF = (RTC_CNTL_SOC_CLK_SEL << 27) | (2 << 12) | (1 << 9) | (4 << 1);

_uart_init();
}

Expand Down
8 changes: 5 additions & 3 deletions examples/1rmttm1637/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ The inner subcycle is 6 steps long and is called **phase** (see `u8Phase`):
#### Connections

```
ESP32.GPIO21 -- X1.CLK
ESP32.GPIO19 -- X1.DIO
ESP32.GPIO25 -- X1.CLK
ESP32.GPIO26 -- X1.DIO
ESP32.GND -- X1.GND
ESP32.VCC -- X1.VCC
```
Expand All @@ -33,4 +33,6 @@ ESP32.VCC -- X1.VCC
and the numbers are smoothly faded in / faded out.

* First, a square should be displayed in the top left corner (`0x63`).
Then, this square should move around the display (clockwise).
Then, this square should move around the display (clockwise).

* Display everything (the 6 phases above) rotated by 180°.
23 changes: 11 additions & 12 deletions examples/1rmttm1637/rmttm1637.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@
#define UART_FREQ_HZ 115200U

// #2: Channels / wires / addresses
#define CLK_GPIO 21U
#define DIO_GPIO 19U
#define CLK_GPIO 25U
#define DIO_GPIO 26U
#define CLK_CH RMT_CH1
#define DIO_CH RMT_CH0

Expand All @@ -43,7 +43,7 @@

typedef struct {
STm1637State *psState;
uint64_t u64tckStart;
uint32_t u32tckStart;
} SReadyCbParam;

// ================ Local function declarations =================
Expand All @@ -69,10 +69,10 @@ static SReadyCbParam gsReadyData;

static void _rmttm1637_ready(void *pvParam) {
SReadyCbParam *psParam = (SReadyCbParam*) pvParam;
uint64_t u64TckStop = timg_ticks(gsTimer);
uart_printf(&gsUART0, "Display ready (failed ACKs: %03X)\tDt: %d ns\n",
uint32_t u32tckStop = (uint32_t)timg_ticks(gsTimer);
uart_printf(&gsUART0, "Display ready (failed ACKs: %03X)\tDt: %u ns\r\n",
psParam->psState->abNak & 0xfff,
TICKS2NS((uint32_t) (u64TckStop - psParam->u64tckStart)));
TICKS2NS(u32tckStop - (uint32_t) psParam->u32tckStart));
}

static void _rmttm1637_init() {
Expand Down Expand Up @@ -100,31 +100,31 @@ static void _rmttm1637_cycle(uint64_t u64Ticks) {
gau8Tm1637Data[i] = gau8NumToSeg[u8DatIdx];
gau8Tm1637Data[TM1637_COLON_POS] |= 0x80;
}
gsReadyData.u64tckStart = timg_ticks(gsTimer);
gsReadyData.u32tckStart = (uint32_t) timg_ticks(gsTimer);
tm1637_flush_full(&gsTm1637State, TM1637_CELLS);
break;
case 1: // remove colon/dot
gau8Tm1637Data[TM1637_COLON_POS] &= 0x7f;
gsReadyData.u64tckStart = timg_ticks(gsTimer);
gsReadyData.u32tckStart = (uint32_t) timg_ticks(gsTimer);
tm1637_flush_range(&gsTm1637State, TM1637_COLON_POS, 1);
break;
case 2: // low brightness
case 3: // high brightness
tm1637_set_brightness(&gsTm1637State, true, u8Phase == 2 ? 2 : 7);
gsReadyData.u64tckStart = timg_ticks(gsTimer);
gsReadyData.u32tckStart = (uint32_t) timg_ticks(gsTimer);
tm1637_flush_brightness(&gsTm1637State);
break;
case 4: // display '-' after colon
for (int i = TM1637_COLON_POS + 1; i < TM1637_CELLS; ++i) {
gau8Tm1637Data[i] = 0x40;
}
gau8Tm1637Data[TM1637_COLON_POS] |= 0x80;
gsReadyData.u64tckStart = timg_ticks(gsTimer);
gsReadyData.u32tckStart = (uint32_t) timg_ticks(gsTimer);
tm1637_flush_range(&gsTm1637State, TM1637_COLON_POS, TM1637_CELLS - TM1637_COLON_POS);
break;
default: // remove colon/dot
gau8Tm1637Data[TM1637_COLON_POS] &= 0x7f;
gsReadyData.u64tckStart = timg_ticks(gsTimer);
gsReadyData.u32tckStart = (uint32_t) timg_ticks(gsTimer);
tm1637_flush_range(&gsTm1637State, TM1637_COLON_POS, 1);
}
// jump to next state
Expand All @@ -141,7 +141,6 @@ static void _rmttm1637_cycle(uint64_t u64Ticks) {
}

// -------------- Interface functions --------------

void prog_init_pro_pre() {
gsUART0.CLKDIV.raw = UART_HZ2CLKDIV(UART_FREQ_HZ, APB_FREQ_HZ);
_rmttm1637_init();
Expand Down
75 changes: 14 additions & 61 deletions modules/tm1637.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
* 4 MHz 666 KHz 103 µs 30 µs 500 KHz 138 µs 40 µs
* 5 MHz 833 KHz 828 µs 24 µs 625 KHz 110 µs 32 µs
*/
#define RMT_FREQ_KHZ 3000U
#define CLK_PERIOD_TICKS 6U

#define TM1637_CLK_FREQ_KHZ 500U
#define RMT_FREQ_KHZ 4000U
#define CLK_PERIOD_TICKS (RMT_FREQ_KHZ / TM1637_CLK_FREQ_KHZ)
#define CLK_HALFPERIOD_TICKS (CLK_PERIOD_TICKS / 2)
#define DIO_DELAY_TICKS 0U ///< delay of DIO signal change to CLK falling edge
#define DIO_DELAY_TICKS 1U ///< delay of DIO signal change to CLK falling edge

// Commands
#define CMD_SETDATA 0x40
Expand Down Expand Up @@ -67,11 +67,12 @@ static void _start_tx_process(STm1637State *psState, SInternals sX);
// ==================== Local Data ================

// ==================== Implementation ================

/**
* When the DIO TX process is over, CLK TX is still running.
* Here we have CLK_PERIOD_TICKS - DIO_DELAY_TICKS to do
* some time consuming calculations.
* Note, here we update the RMT RAM of the CLK channel, however, as we modify olny its first 2 registers,
* Note, here we update the RMT RAM of the CLK channel, however, as we modify only its first 2 registers,
* the update does not disturb the ongoing CLK TX process.
* @param pvParam TM1637 state descriptor.
*/
Expand Down Expand Up @@ -135,15 +136,15 @@ static inline void _init_clkseq(ERmtChannel eChannel) {
*/
static inline void _update_clkseq(ERmtChannel eChannel, bool bStop, bool bStart) {
RegAddr prClkRam = rmt_ram_addr(eChannel, 1, 0); // cppcheck-suppress unusedVariable
prClkRam[1] = RMT_ENTRYPAIR(0, CLK_HALFPERIOD_TICKS, 1, CLK_HALFPERIOD_TICKS);
if (bStart && !bStop) {
prClkRam[1] = RMT_ENTRYPAIR(0, CLK_HALFPERIOD_TICKS, 1, CLK_HALFPERIOD_TICKS); // the clk period of LSB (set to its initial value)
if (bStart && !bStop) { // very first byte
prClkRam[0] = RMT_ENTRYPAIR(1, 1, 1, CLK_HALFPERIOD_TICKS - 1); // 0.5 periods
} else if (bStart && bStop) {
} else if (bStart && bStop) { // stop followed by start
prClkRam[0] = RMT_ENTRYPAIR(0, CLK_HALFPERIOD_TICKS, 1, 3 * CLK_HALFPERIOD_TICKS); // 2 periods
} else if (!bStart && bStop) {
} else if (!bStart && bStop) { // only stop (terminating stop)
prClkRam[0] = RMT_ENTRYPAIR(0, CLK_HALFPERIOD_TICKS, 1, 2 * CLK_HALFPERIOD_TICKS); // 1.5 periods
prClkRam[1] = 0;
} else {
} else { // no start, no stop
prClkRam[0] = RMT_ENTRYPAIR(0, 1, 0, 1);
prClkRam[1] -= 2;
}
Expand Down Expand Up @@ -176,7 +177,7 @@ static inline void _dat_dioseq(RegAddr prDioRam, uint8_t u8Dat) {
* @param u8Dat Bit sequence to represent on DIO (except for the case when STOP is not followed by START).
*/
static inline void _update_dioseq(ERmtChannel eChannel, bool bStop, bool bStart, uint8_t u8Dat) {
static uint32_t u32EntryPairStart = RMT_ENTRYPAIR(0, 1, 0, CLK_HALFPERIOD_TICKS - 1); // 0.5 periods
static uint32_t u32EntryPairStart = RMT_ENTRYPAIR(0, 1, 0, CLK_HALFPERIOD_TICKS - 1 + DIO_DELAY_TICKS); // 0.5 periods + delay
static uint32_t u32EntryPairStop = RMT_ENTRYPAIR(0, 2 * CLK_HALFPERIOD_TICKS, 1, CLK_HALFPERIOD_TICKS); // 1.5 periods
RegAddr prDioRam = rmt_ram_addr(eChannel, 1, 0); // cppcheck-suppress unusedVariable
if (bStart && !bStop) {
Expand All @@ -191,7 +192,7 @@ static inline void _update_dioseq(ERmtChannel eChannel, bool bStop, bool bStart,
prDioRam[1] = 0;
} else {
_dat_dioseq(prDioRam, u8Dat);
prDioRam[0] + DIO_DELAY_TICKS;
prDioRam[0] += DIO_DELAY_TICKS;
}
}

Expand All @@ -207,8 +208,7 @@ static void _next_byte(void *pvParam) {
STm1637State *psParam = (STm1637State*) pvParam;

++psParam->sByteI.u8Cur;
rmt_start_tx(psParam->sIface.eClkCh, true);
rmt_start_tx(psParam->sIface.eDioCh, true);
rmt_start_tx_sync(psParam->sIface.eClkCh, psParam->sIface.eDioCh, true);

}

Expand Down Expand Up @@ -253,12 +253,6 @@ static void _rmt_config_channel(const STm1637Iface *psIface, uint8_t u8Divisor)
}

// ============== Interface functions ==============
/**
* Initializes a state object.
* @param psIface Defines TM1637 communication interface (GPIO pins, RMT channels).
* @param pu8Data Source of 7 segment characters to display.
* @return Initialized TM1637 state descriptor.
*/
STm1637State tm1637_config(const STm1637Iface *psIface, uint8_t *pu8Data) {
return (STm1637State){
.sIface = *psIface,
Expand All @@ -267,11 +261,6 @@ STm1637State tm1637_config(const STm1637Iface *psIface, uint8_t *pu8Data) {
.pvReadyCbArg = NULL};
}

/**
* Initializes TM1637 communication peripherals.
* @param psState TM1637 state descriptor.
* @param u32ApbClkFreq APB clock frequency (used to calculate RMT divisor).
*/
void tm1637_init(STm1637State *psState, uint32_t u32ApbClkFreq) {
rmt_init_channel(psState->sIface.eClkCh, psState->sIface.u8ClkPin, true);
rmt_init_channel(psState->sIface.eDioCh, psState->sIface.u8DioPin, true);
Expand All @@ -295,38 +284,15 @@ void tm1637_deinit(STm1637State *psState) {
// release GPIO
}

/**
* Sets TM1637 brightness value.
* Note, this function does not trigger communication. Either tm1637_flush_full()
* or tm1637_flush_brightness() must be invoked in order to apply changes.
* @param psState TM1637 state descriptor.
* @param bOn Turn display on (false: turn off).
* @param u8Value Valid range: [0..7] 0: lowest (1/16), 7: highest (14/16) brightness.
*/
void tm1637_set_brightness(STm1637State *psState, bool bOn, uint8_t u8Value) {
psState->u8Brightness = (bOn ? 0x08 : 0x00) | (u8Value & 0x07);
}

/**
* Set callback function and parameter.
* This callback function will be invoked when any communication process is over.
* @param psState TM1637 state descriptor.
* @param fHandler Callback function.
* @param pvArg Parameter of the callback function.
*/
void tm1637_set_readycb(STm1637State *psState, Isr fHandler, void *pvArg) {
psState->fReadyCb = fHandler;
psState->pvReadyCbArg = pvArg;
}

/**
* Full flush consists of 3 TM1637 commands:
* 1. CMD_SETDATA: set write mode (with incremental addressing).
* 2. CMD_SETADDRESS: set initial address (and write data to display registers).
* 3. CMD_CTRLDISPLAY: set brightness.
* @param psState TM1637 state descriptor.
* @param u8Len Number of cells/characters to update in the display registers.
*/
void tm1637_flush_full(STm1637State *psState, uint8_t u8Len) {
// reset address mode and address
psState->au8Bytes[0] = CMD_SETDATA;
Expand All @@ -341,13 +307,6 @@ void tm1637_flush_full(STm1637State *psState, uint8_t u8Len) {
_start_tx_process(psState, (SInternals){3 + u8Len, 3});
}

/**
* Limited display register update.
* A single command is sent (CMD_SETADDRESS) followed by data bytes.
* @param psState TM1637 state descriptor.
* @param u8Pos Start cell/character update at this position.
* @param u8Len Number of data bytes to send (number of cells/characters to update).
*/
void tm1637_flush_range(STm1637State *psState, uint8_t u8Pos, uint8_t u8Len) {
psState->au8Bytes[0] = CMD_SETADDRESS | (u8Pos & 0x07);
for (uint8_t i = 0; i < u8Len; ++i) {
Expand All @@ -357,12 +316,6 @@ void tm1637_flush_range(STm1637State *psState, uint8_t u8Pos, uint8_t u8Len) {
_start_tx_process(psState, (SInternals){1 + u8Len, 1});
}

/**
* Sets brightness on the TM1637 device.
* A single command is sent (CMD_CTRLDISPLAY) without any data bytes.
* tm1637_set_brightness() must be called before this function.
* @param psState TM1637 state descriptor.
*/
void tm1637_flush_brightness(STm1637State *psState) {
psState->au8Bytes[0] = CMD_CTRLDISPLAY | (psState->u8Brightness & 0x0f);
_start_tx_process(psState, (SInternals){1, 1});
Expand Down
55 changes: 55 additions & 0 deletions modules/tm1637.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,68 @@ extern "C" {
} STm1637State;


/**
* Initializes a state object.
* @param psIface Defines TM1637 communication interface (GPIO pins, RMT channels).
* @param pu8Data Source of 7 segment characters to display.
* @return Initialized TM1637 state descriptor.
*/
STm1637State tm1637_config(const STm1637Iface *psIface, uint8_t *pu8Data);

/**
* Initializes TM1637 communication peripherals.
* @param psState TM1637 state descriptor.
* @param u32ApbClkFreq APB clock frequency, used for calculating RMT divisor (and implicitly TM1637 CLK frequency).
* The default TM1637 CLK frequency is 500KHz. If the real APB clk freq is 80.000.000, but u32ApbClkFreq is set to 40.000.000,
* the TM1637 CLK frequency will be 1MHz, etc. The TM1637 CLK frequency can be tuned up to 2.5MHz (experimental).
*/
void tm1637_init(STm1637State *psState, uint32_t u32ApbClkFreq);
void tm1637_deinit(STm1637State *psState);

/**
* Sets TM1637 brightness value.
* Note, this function does not trigger communication. Either tm1637_flush_full()
* or tm1637_flush_brightness() must be invoked in order to apply changes.
* @param psState TM1637 state descriptor.
* @param bOn Turn display on (false: turn off).
* @param u8Value Valid range: [0..7] 0: lowest (1/16), 7: highest (14/16) brightness.
*/
void tm1637_set_brightness(STm1637State *psState, bool bOn, uint8_t u8Value);

/**
* Set callback function and parameter.
* This callback function will be invoked when any communication process is over.
* @param psState TM1637 state descriptor.
* @param fHandler Callback function.
* @param pvArg Parameter of the callback function.
*/
void tm1637_set_readycb(STm1637State *psState, Isr fHandler, void *pvArg);

/**
* Full flush consists of 3 TM1637 commands:
* 1. CMD_SETDATA: set write mode (with incremental addressing).
* 2. CMD_SETADDRESS: set initial address (and write data to display registers).
* 3. CMD_CTRLDISPLAY: set brightness.
* @param psState TM1637 state descriptor.
* @param u8Len Number of cells/characters to update in the display registers.
*/
void tm1637_flush_full(STm1637State *psState, uint8_t u8Len);

/**
* Limited display register update.
* A single command is sent (CMD_SETADDRESS) followed by data bytes.
* @param psState TM1637 state descriptor.
* @param u8Pos Start cell/character update at this position.
* @param u8Len Number of data bytes to send (number of cells/characters to update).
*/

void tm1637_flush_range(STm1637State *psState, uint8_t u8Pos, uint8_t u8Len);
/**
* Sets brightness on the TM1637 device.
* A single command is sent (CMD_CTRLDISPLAY) without any data bytes.
* tm1637_set_brightness() must be called before this function.
* @param psState TM1637 state descriptor.
*/
void tm1637_flush_brightness(STm1637State *psState);

#ifdef __cplusplus
Expand Down
Loading
Loading