#include "ch32fun_spi.h" extern uint8_t * make_output_buffer(mrb_vm *vm, mrb_value v[], int argc, int start_idx, int *ret_bufsiz); #if !MRBC_USE_STRING extern mrbc_value mrbc_array_new_alloc(mrbc_vm *vm, const uint8_t *c_array, int size); #endif void spi_init(){ RCC->APB2PCENR |= RCC_APB2Periph_SPI1; //PA4 NSS funPinMode(5,GPIO_CFGLR_OUT_50Mhz_AF_PP); //PA5 SCK funPinMode(6,GPIO_CFGLR_IN_FLOAT); //PA6 MISO funPinMode(7,GPIO_CFGLR_OUT_50Mhz_AF_PP); //PA7 MOSI } #define SPI_TIMEOUT_MAX 100000 void spi_transfer(uint8_t *buf, uint32_t len) { uint32_t timeout; for (uint32_t i = 0; i < len; i++) { timeout = SPI_TIMEOUT_MAX; while (!(SPI1->STATR & SPI_STATR_TXE)) { if (--timeout == 0) return; } SPI1->DATAR = buf[i]; timeout = SPI_TIMEOUT_MAX; while (!(SPI1->STATR & SPI_STATR_RXNE)) { if (--timeout == 0) return; } buf[i] = SPI1->DATAR; } timeout = SPI_TIMEOUT_MAX; while (SPI1->STATR & SPI_STATR_BSY) { if (--timeout == 0) return; } } void c_spi_setmode(mrbc_vm *vm, mrbc_value v[], int argc){ MRBC_KW_ARG( unit, frequency, mode, first_bit ); uint32_t spi_freq = 1000000; int spi_mode = 0; int spi_first_bit = 0; if( MRBC_KW_ISVALID(frequency) ) spi_freq = mrbc_integer(frequency); if( MRBC_KW_ISVALID(first_bit) ) spi_first_bit = mrbc_integer(first_bit); if( MRBC_KW_ISVALID(mode) ) spi_mode = mrbc_integer(mode); uint32_t ratio = (FUNCONF_SYSTEM_CORE_CLOCK / spi_freq); //FHCLK uint8_t scale=0; ratio--; while(ratio>>=1) scale++; if(scale>7) scale=7; uint16_t val=0; val |= SPI_CTLR1_MSTR; val |= (scale<<3); // SPI_CTLR1_BR val |= spi_mode & 3; // SPI_CTLR1_CPHA | SPI_CTLR1_CPOL #if defined( CH32V20x ) val |= (spi_first_bit & 1) << 7 ; #else val |= SPI_CTLR1_LSBFIRST * (spi_first_bit & 1) ; #endif val |= SPI_CTLR1_SSM | SPI_CTLR1_SSI; // software SS SPI1->CTLR1 = val | SPI_CTLR1_SPE; MRBC_KW_DELETE( unit, frequency, mode, first_bit ); } void c_spi_new(mrb_vm *vm, mrb_value *v, int argc){ v[0] = mrbc_instance_new(vm, v[0].cls, 0); spi_init(); c_spi_setmode( vm, v, argc ); } void c_spi_write(mrb_vm *vm, mrb_value *v, int argc){ uint8_t *buf = 0; int bufsiz = 0; if(argc>0){ buf = make_output_buffer( vm, v, argc, 1, &bufsiz ); spi_transfer(buf, bufsiz); mrbc_free( vm, buf ); } SET_RETURN( mrbc_integer_value(bufsiz) ); } void c_spi_read(mrb_vm *vm, mrb_value *v, int argc){ mrbc_value ret = mrbc_nil_value(); if(argc>0){ int size = GET_INT_ARG(1); uint8_t *buf = mrbc_alloc(vm, size); memset(buf, 0, size); spi_transfer(buf, size); #if MRBC_USE_STRING ret = mrbc_string_new_alloc(vm, buf, size); #else ret = mrbc_array_new_alloc( vm, buf, size); mrbc_free( vm, buf ); #endif } SET_RETURN(ret); } void c_spi_transfer(mrb_vm *vm, mrb_value *v, int argc){ mrbc_value ret = mrbc_nil_value(); uint8_t *buf = 0; int bufsiz = 0; if(argc>0){ buf = make_output_buffer( vm, v, 1, 1, &bufsiz ); if(argc>1){ int additional_read_bytes = GET_INT_ARG(2); uint8_t *buf2 = (uint8_t *) mrbc_realloc(vm, buf, bufsiz + additional_read_bytes); buf = buf2; memset(buf + bufsiz, 0, additional_read_bytes); bufsiz += additional_read_bytes; } spi_transfer(buf, bufsiz); #if MRBC_USE_STRING ret = mrbc_string_new_alloc(vm, buf, bufsiz); #else ret = mrbc_array_new_alloc( vm, buf, bufsiz); mrbc_free( vm, buf ); #endif } SET_RETURN(ret); } void mrbc_init_class_spi(void){ mrb_class *spi = mrbc_define_class(0, "SPI", mrbc_class_object); mrbc_define_method(0, spi, "new", c_spi_new); mrbc_define_method(0, spi, "setmode", c_spi_setmode); mrbc_define_method(0, spi, "read", c_spi_read); mrbc_define_method(0, spi, "write", c_spi_write); mrbc_define_method(0, spi, "transfer", c_spi_transfer); mrbc_set_class_const(spi, mrbc_str_to_symid("LSB_FIRST"), &mrbc_integer_value(1)); mrbc_set_class_const(spi, mrbc_str_to_symid("MSB_FIRST"), &mrbc_integer_value(0)); }