From dfcba8ee416c093b1fa7dc47e0d7872fe277537d Mon Sep 17 00:00:00 2001 From: Kizarm Date: Mon, 8 Apr 2024 20:55:20 +0200 Subject: [PATCH] add i2c --- ch32v003/gcc.mk | 2 +- common/pcmdma.h | 1 + i2c/Makefile | 54 +++++++++++++++++++++++++++ i2c/ch32v003 | 1 + i2c/common | 1 + i2c/i2cmaster.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++ i2c/i2cmaster.h | 28 ++++++++++++++ i2c/main.cpp | 34 +++++++++++++++++ midi/Makefile | 3 +- midi/linux/gcc.mk | 12 ++++++ midi/linux/gpio.h | 37 +++++++++++++++++++ midi/linux/pcmdma.cpp | 79 ++++++++++++++++++++++++++++++++++++++++ midi/pwmconfig.h | 3 ++ 13 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 i2c/Makefile create mode 120000 i2c/ch32v003 create mode 120000 i2c/common create mode 100644 i2c/i2cmaster.cpp create mode 100644 i2c/i2cmaster.h create mode 100644 i2c/main.cpp create mode 100644 midi/linux/gcc.mk create mode 100644 midi/linux/gpio.h create mode 100644 midi/linux/pcmdma.cpp diff --git a/ch32v003/gcc.mk b/ch32v003/gcc.mk index a13e1d2..4d62f6d 100644 --- a/ch32v003/gcc.mk +++ b/ch32v003/gcc.mk @@ -7,7 +7,7 @@ SIZE = $(PREFIX)size DUMP = $(PREFIX)objdump COPY = $(PREFIX)objcopy OBJS += startup.o system.o -CFLAGS+= -Os +CFLAGS+= -Os -I/usr/include/newlib CCPU = -march=rv32ec -mabi=ilp32e MCPU = $(CCPU) CFLAGS+= $(MCPU) diff --git a/common/pcmdma.h b/common/pcmdma.h index 9bbc3d4..14ea7c0 100644 --- a/common/pcmdma.h +++ b/common/pcmdma.h @@ -17,6 +17,7 @@ class PcmDma { OneWay * src; public: explicit PcmDma () noexcept; + uint16_t * getBuff () { return buffer; }; void attach (OneWay & s) { src = & s; } void send (const bool b) { if (!src) return; diff --git a/i2c/Makefile b/i2c/Makefile new file mode 100644 index 0000000..cf2ab0e --- /dev/null +++ b/i2c/Makefile @@ -0,0 +1,54 @@ +# ch32v003 +TARGET?= ch32v003 +TOOL ?= gcc + +PRJ = example + +VPATH = . ./$(TARGET) ./common +BLD = ./build/ +DFLAGS = -d +LFLAGS = -g +LDLIBS = +BFLAGS = --strip-unneeded + +CFLAGS = -MMD -Wall -ggdb -fno-exceptions -ffunction-sections -fdata-sections +CFLAGS+= -I. -I./$(TARGET) -I./common -I/usr/include/newlib -DUSE_HSE=1 +DEL = rm -f + +# zdrojaky +OBJS = main.o i2cmaster.o usart.o print.o + +include $(TARGET)/$(TOOL).mk +BOBJS = $(addprefix $(BLD),$(OBJS)) + +all: $(BLD) $(PRJ).elf +# ... atd. +-include $(BLD)*.d +# linker +$(PRJ).elf: $(BOBJS) + -@echo [LD $(TOOL),$(TARGET)] $@ + @$(LD) $(LFLAGS) -o $(PRJ).elf $(BOBJS) $(LDLIBS) + -@echo "size:" + @$(SIZE) $(PRJ).elf + -@echo "listing:" + $(DUMP) $(DFLAGS) $(PRJ).elf > $(PRJ).lst + -@echo "OK." + $(COPY) $(BFLAGS) -O binary $(PRJ).elf $(PRJ).bin + $(COPY) $(BFLAGS) -O ihex $(PRJ).elf $(PRJ).hex +# preloz co je potreba +$(BLD)%.o: %.c + -@echo [CC $(TOOL),$(TARGET)] $@ + @$(CC) -c $(CFLAGS) $< -o $@ +$(BLD)%.o: %.cpp + -@echo [CX $(TOOL),$(TARGET)] $@ + @$(CXX) -std=c++17 -fno-rtti -c $(CFLAGS) $< -o $@ +$(BLD): + mkdir $(BLD) +sin.c: sin.py + ./sin.py +flash: $(PRJ).elf + minichlink -w $(PRJ).bin flash -b +# vycisti +clean: + $(DEL) $(BLD)* *.lst *.bin *.hex *.elf *.map *~ +.PHONY: all clean diff --git a/i2c/ch32v003 b/i2c/ch32v003 new file mode 120000 index 0000000..0bcf9a1 --- /dev/null +++ b/i2c/ch32v003 @@ -0,0 +1 @@ +../ch32v003/ \ No newline at end of file diff --git a/i2c/common b/i2c/common new file mode 120000 index 0000000..8332399 --- /dev/null +++ b/i2c/common @@ -0,0 +1 @@ +../common/ \ No newline at end of file diff --git a/i2c/i2cmaster.cpp b/i2c/i2cmaster.cpp new file mode 100644 index 0000000..6779f61 --- /dev/null +++ b/i2c/i2cmaster.cpp @@ -0,0 +1,85 @@ +#include "system.h" +#include "i2cmaster.h" +#include "print.h" + +I2CMaster::I2CMaster() noexcept { + RCC.APB1PCENR.B.I2C1EN = SET; + RCC.APB2PCENR.B.IOPCEN = SET; + + // GPIO Alternate Config - default SCL/PC2, SDA/PC1 + GPIOC.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto { + r.B.CNF1 = 3u; + r.B.MODE1 = 1u; + r.B.CNF2 = 3u; + r.B.MODE2 = 1u; + return r.R; + }); + + RCC.APB1PRSTR.B.I2C1RST = SET; + RCC.APB1PRSTR.B.I2C1RST = RESET; + + I2C1.CTLR2.B.FREQ = 48u; + I2C1.CKCFGR.B.CCR = 480u; + I2C1.CTLR1.B.PE = SET; +} +bool I2CMaster::Send(const unsigned char addr, const unsigned char * data, const unsigned int len) { + bool result = false; + do { + if (! send_address(addr & ~1u)) break; + + if (data == nullptr) { return stop_condition(); } + + for (unsigned n=0u; n bool { return I2C1.STAR1.B.TxE == RESET; })) break; + I2C1.DATAR.B.DATAR = to_send; + } + if (! wait_for([]() -> bool { return I2C1.STAR1.B.BTF == RESET; })) break; + result = true; + } while (false); + return result and stop_condition(); +} +bool I2CMaster::Receive (const unsigned char addr, unsigned char * data, const unsigned int len) { + bool result = false; + do { + if (! send_address(addr | 1u)) break; + + I2C1.CTLR1.B.ACK = SET; + for (unsigned n=0u; n bool { return I2C1.STAR1.B.RxNE == RESET; })) break; + data [n] = I2C1.DATAR.B.DATAR; + } + I2C1.CTLR1.B.ACK = RESET; + if (! wait_for([]() -> bool { return I2C1.STAR1.B.RxNE == RESET; })) break; + data [len-1] = I2C1.DATAR.B.DATAR; + result = true; + } while (false); + return result and stop_condition(); +} +bool I2CMaster::send_address(const unsigned char addr) { + I2C1.CTLR1.B.START = SET; + if (! wait_for([]() -> bool { return I2C1.STAR1.B.SB == RESET; })) return false; + I2C1.DATAR.B.DATAR = addr; + if (! wait_for([]() -> bool { return I2C1.STAR1.B.ADDR == RESET; })) return false; + volatile unsigned x = I2C1.STAR2.R; (void) x; + return true; +} +bool I2CMaster::stop_condition() { + I2C1.CTLR1.B.STOP = SET; + return wait_for([]() -> bool { return I2C1.CTLR1.B.STOP == SET; }); +} + +void I2CMaster::FindActive(Print& print) { + const char * blank = " \r"; + for (unsigned addr = 0u; addr < 0xFF; addr += 2u) { + print << "addr = " << (int) addr; + if (send_address(addr & ~1u)) { + print << " ... OK\r\n"; + } else { + print << blank; + } + stop_condition(); + } + print << blank; +} + diff --git a/i2c/i2cmaster.h b/i2c/i2cmaster.h new file mode 100644 index 0000000..dc81388 --- /dev/null +++ b/i2c/i2cmaster.h @@ -0,0 +1,28 @@ +#ifndef I2CMASTER_H +#define I2CMASTER_H + +class Print; + +class I2CMaster { + public: + explicit I2CMaster () noexcept; + bool Send (const unsigned char addr, const unsigned char * data, const unsigned len); + bool Receive (const unsigned char addr, unsigned char * data, const unsigned len); + + void FindActive (Print & print); + protected: + bool stop_condition (); + bool send_address (const unsigned char addr); + + template bool wait_for (F f, const unsigned timeout = 10000) { + volatile unsigned counter = 0u; + while (f()) { + counter += 1u; + if (counter > timeout) return false; + } + return true; + } + +}; + +#endif // I2CMASTER_H diff --git a/i2c/main.cpp b/i2c/main.cpp new file mode 100644 index 0000000..62e22d3 --- /dev/null +++ b/i2c/main.cpp @@ -0,0 +1,34 @@ +#include "i2cmaster.h" +#include "usart.h" +#include "print.h" +////////////////////////////////////// +void delay () { + volatile unsigned n = 5'000'000u; + while (n--); +} +static I2CMaster iic; +static Usart serial (115200); +static Print cout (DEC); +static const unsigned char addr = 0x90u; +static const unsigned char cmd1 [] = {1u, 6u}; +static const unsigned char cmd2 [] = {0u}; + +int main () { + cout += serial; + delay(); + iic.FindActive(cout); + iic.Send(addr, cmd1 , 2); + iic.Send(addr, cmd2 , 1); + + for (;;) { + delay(); + unsigned char buf [2]; + if (iic.Receive (addr, buf, 2)) { + const char * d = buf [1] != 0 ? ".5" : ".0"; + cout << "T = " << (int) buf [0] << d << EOL; + } else { + cout << "error\r\n"; + } + } + return 0; +} diff --git a/midi/Makefile b/midi/Makefile index f7d0916..73cd606 100644 --- a/midi/Makefile +++ b/midi/Makefile @@ -1,6 +1,7 @@ # ch32v003 TARGET?= ch32v003 #TARGET?= stm32f051 +#TARGET?= linux TOOL ?= gcc #TOOL ?= clang @@ -14,7 +15,7 @@ LDLIBS = BFLAGS = --strip-unneeded CFLAGS = -MMD -Wall -ggdb -fno-exceptions -ffunction-sections -fdata-sections -CFLAGS+= -I. -I./common -I./$(TARGET) -I/usr/include/newlib -DHAVE_CONFIG=1 +CFLAGS+= -I. -I./common -I./$(TARGET) -DHAVE_CONFIG=1 DEL = rm -f # zdrojaky diff --git a/midi/linux/gcc.mk b/midi/linux/gcc.mk new file mode 100644 index 0000000..f689848 --- /dev/null +++ b/midi/linux/gcc.mk @@ -0,0 +1,12 @@ +# Use gcc / binutils toolchain +PREFIX = +CC = $(PREFIX)gcc +CXX = $(PREFIX)g++ +LD = $(PREFIX)g++ +SIZE = $(PREFIX)size +DUMP = $(PREFIX)objdump +COPY = $(PREFIX)objcopy +CFLAGS+= -Os + +LFLAGS+= -Wl,--Map=$(@:%.elf=%.map),--gc-sections +LDLIBS+= -lc -lpthread -lasound diff --git a/midi/linux/gpio.h b/midi/linux/gpio.h new file mode 100644 index 0000000..f6270d7 --- /dev/null +++ b/midi/linux/gpio.h @@ -0,0 +1,37 @@ +#ifndef _GPIO_CLASS_H_ +#define _GPIO_CLASS_H_ +#include +enum GPIO_MODE : uint32_t { + GPIO_Speed_In = 0u, + GPIO_Speed_10MHz = 1u, + GPIO_Speed_2MHz = 2u, + GPIO_Speed_50MHz = 3u, +}; +enum GPIO_CNF : uint32_t { + GPIO_AI_PPO = 0u, + GPIO_FI_ODO = 1u << 2, + GPIO_UPDI_MPPO = 2u << 2, + GPIO_none_MPDO = 3u << 2, +}; +enum GPIOPuPd_TypeDef { + GPIO_PuPd_NOPULL = 0x00, + GPIO_PuPd_UP = 0x01, + GPIO_PuPd_DOWN = 0x02 +}; + +class GpioClass { + const uint32_t pin; + public: + explicit constexpr GpioClass (const uint32_t _pin, const uint32_t _mode = GPIO_AI_PPO) noexcept + : pin(_pin) { + } + void operator<< (const bool b) const { + } + operator bool () const { + return false; + } + void setPuPd (GPIOPuPd_TypeDef p) { + } +}; + +#endif // _GPIO_CLASS_H_ diff --git a/midi/linux/pcmdma.cpp b/midi/linux/pcmdma.cpp new file mode 100644 index 0000000..32c6101 --- /dev/null +++ b/midi/linux/pcmdma.cpp @@ -0,0 +1,79 @@ +#include "pcmdma.h" +#include +#include +#include + +struct Sample { + short l; + short r; +}__attribute__((packed)); + +static constexpr unsigned BufLen = FULL_LEN; + +static const char *device = "default"; +static snd_pcm_t *handle; + +static int open_alsa_device (int channels, int srate) { + int err; + if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) { + printf("Playback open error: %s\n", snd_strerror(err)); + return 0; + } + if ((err = snd_pcm_set_params(handle, + SND_PCM_FORMAT_S16_LE, + SND_PCM_ACCESS_RW_INTERLEAVED, + channels, + srate, + 1, + 500000)) < 0) { /* 0.5sec */ + printf("Playback open error: %s\n", snd_strerror(err)); + return 0; + } + return 1; +} +int alsa_write (const void * buf, int len) { + snd_pcm_sframes_t frames; + int err = 0; + frames = snd_pcm_writei(handle, buf, len); + if (frames < 0) + frames = snd_pcm_recover(handle, frames, 0); + if (frames < 0) { + printf("snd_pcm_writei failed: %s\n", snd_strerror(err)); + return 0; + } + if (frames > 0 && frames < (long)sizeof(buf)) + printf("Short write (expected %i, wrote %li)\n", len, frames); + return len; +} +void sig_handler (int signum) { + printf(" - Received signal %d\n", signum); + ::exit (0); +} + +static constexpr int CC = MAXPWM / 2; + +static pthread_t rc; + +void * WriteHandler (void * data) { + printf ("Start thread\n"); + PcmDma * pA = (PcmDma *) data; + Sample buf [BufLen]; + uint16_t * pbuf = pA->getBuff(); + for (;;) { + pA->send (false); + pA->send (true); + //printf ("pass\n"); + for (unsigned i=0; i