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
|
||||
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)
|
||||
|
|
|
@ -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;
|
||||
|
|
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
|
||||
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
|
||||
|
|
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__
|
||||
#define LED_CFG GpioPortA,0
|
||||
#define BUT_CFG GpioPortA,3,GPIO_Mode_IN
|
||||
#elif __linux__
|
||||
#define LED_CFG 0
|
||||
#define BUT_CFG 3
|
||||
#else
|
||||
#error "bad target"
|
||||
#endif
|
||||
|
|
Loading…
Reference in a new issue