add i2c
This commit is contained in:
parent
de48701e8c
commit
dfcba8ee41
13 changed files with 338 additions and 2 deletions
|
@ -7,7 +7,7 @@ SIZE = $(PREFIX)size
|
||||||
DUMP = $(PREFIX)objdump
|
DUMP = $(PREFIX)objdump
|
||||||
COPY = $(PREFIX)objcopy
|
COPY = $(PREFIX)objcopy
|
||||||
OBJS += startup.o system.o
|
OBJS += startup.o system.o
|
||||||
CFLAGS+= -Os
|
CFLAGS+= -Os -I/usr/include/newlib
|
||||||
CCPU = -march=rv32ec -mabi=ilp32e
|
CCPU = -march=rv32ec -mabi=ilp32e
|
||||||
MCPU = $(CCPU)
|
MCPU = $(CCPU)
|
||||||
CFLAGS+= $(MCPU)
|
CFLAGS+= $(MCPU)
|
||||||
|
|
|
@ -17,6 +17,7 @@ class PcmDma {
|
||||||
OneWay * src;
|
OneWay * src;
|
||||||
public:
|
public:
|
||||||
explicit PcmDma () noexcept;
|
explicit PcmDma () noexcept;
|
||||||
|
uint16_t * getBuff () { return buffer; };
|
||||||
void attach (OneWay & s) { src = & s; }
|
void attach (OneWay & s) { src = & s; }
|
||||||
void send (const bool b) {
|
void send (const bool b) {
|
||||||
if (!src) return;
|
if (!src) return;
|
||||||
|
|
54
i2c/Makefile
Normal file
54
i2c/Makefile
Normal file
|
@ -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
|
1
i2c/ch32v003
Symbolic link
1
i2c/ch32v003
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../ch32v003/
|
1
i2c/common
Symbolic link
1
i2c/common
Symbolic link
|
@ -0,0 +1 @@
|
||||||
|
../common/
|
85
i2c/i2cmaster.cpp
Normal file
85
i2c/i2cmaster.cpp
Normal file
|
@ -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<len; n++) {
|
||||||
|
const unsigned char to_send = data [n];
|
||||||
|
if (! wait_for([]() -> 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<len-1; n++) {
|
||||||
|
if (! wait_for([]() -> 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;
|
||||||
|
}
|
||||||
|
|
28
i2c/i2cmaster.h
Normal file
28
i2c/i2cmaster.h
Normal file
|
@ -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<typename F> 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
|
34
i2c/main.cpp
Normal file
34
i2c/main.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
# ch32v003
|
# ch32v003
|
||||||
TARGET?= ch32v003
|
TARGET?= ch32v003
|
||||||
#TARGET?= stm32f051
|
#TARGET?= stm32f051
|
||||||
|
#TARGET?= linux
|
||||||
TOOL ?= gcc
|
TOOL ?= gcc
|
||||||
#TOOL ?= clang
|
#TOOL ?= clang
|
||||||
|
|
||||||
|
@ -14,7 +15,7 @@ LDLIBS =
|
||||||
BFLAGS = --strip-unneeded
|
BFLAGS = --strip-unneeded
|
||||||
|
|
||||||
CFLAGS = -MMD -Wall -ggdb -fno-exceptions -ffunction-sections -fdata-sections
|
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
|
DEL = rm -f
|
||||||
|
|
||||||
# zdrojaky
|
# zdrojaky
|
||||||
|
|
12
midi/linux/gcc.mk
Normal file
12
midi/linux/gcc.mk
Normal file
|
@ -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
|
37
midi/linux/gpio.h
Normal file
37
midi/linux/gpio.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef _GPIO_CLASS_H_
|
||||||
|
#define _GPIO_CLASS_H_
|
||||||
|
#include <stdint.h>
|
||||||
|
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_
|
79
midi/linux/pcmdma.cpp
Normal file
79
midi/linux/pcmdma.cpp
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#include "pcmdma.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <alsa/asoundlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
|
||||||
|
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<BufLen; i++) {
|
||||||
|
const short s = (pbuf [i] - CC) * 32;
|
||||||
|
buf[i].l = s; buf[i].r = s;
|
||||||
|
}
|
||||||
|
alsa_write (buf, BufLen);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
PcmDma::PcmDma() noexcept : pL(buffer), pH(buffer + HALF_LEN), src(nullptr) {
|
||||||
|
signal (SIGINT, sig_handler);
|
||||||
|
open_alsa_device(2, 24000);
|
||||||
|
pthread_create (&rc, NULL, WriteHandler, this);
|
||||||
|
}
|
|
@ -10,6 +10,9 @@ static constexpr unsigned MAXPWM = 2000u;
|
||||||
#elif __arm__
|
#elif __arm__
|
||||||
#define LED_CFG GpioPortA,0
|
#define LED_CFG GpioPortA,0
|
||||||
#define BUT_CFG GpioPortA,3,GPIO_Mode_IN
|
#define BUT_CFG GpioPortA,3,GPIO_Mode_IN
|
||||||
|
#elif __linux__
|
||||||
|
#define LED_CFG 0
|
||||||
|
#define BUT_CFG 3
|
||||||
#else
|
#else
|
||||||
#error "bad target"
|
#error "bad target"
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue