From 061fd8bec80c91fdc7c85df71692710ca6cabc98 Mon Sep 17 00:00:00 2001 From: Edward Emelianov Date: Fri, 20 Feb 2026 23:38:29 +0300 Subject: [PATCH] add SPI (not tested yet) --- F3:F303/InterfaceBoard/Makefile | 1 + F3:F303/InterfaceBoard/Readme.md | 2 +- F3:F303/InterfaceBoard/hardware.c | 2 +- F3:F303/InterfaceBoard/main.c | 14 ++- F3:F303/InterfaceBoard/multiiface.bin | Bin 27996 -> 28576 bytes .../InterfaceBoard/multiiface.creator.user | 2 +- F3:F303/InterfaceBoard/multiiface.files | 2 + F3:F303/InterfaceBoard/spi.c | 108 ++++++++++++++++++ F3:F303/InterfaceBoard/spi.h | 27 +++++ F3:F303/InterfaceBoard/usart.c | 6 + F3:F303/InterfaceBoard/usb_dev.c | 6 +- F3:F303/InterfaceBoard/usb_dev.h | 1 + F3:F303/InterfaceBoard/version.inc | 4 +- 13 files changed, 167 insertions(+), 8 deletions(-) create mode 100644 F3:F303/InterfaceBoard/spi.c create mode 100644 F3:F303/InterfaceBoard/spi.h diff --git a/F3:F303/InterfaceBoard/Makefile b/F3:F303/InterfaceBoard/Makefile index 6659b99..c98577d 100644 --- a/F3:F303/InterfaceBoard/Makefile +++ b/F3:F303/InterfaceBoard/Makefile @@ -3,6 +3,7 @@ BINARY := multiiface MCU := F303xc # change this linking script depending on particular MCU model, LDSCRIPT := stm32f303xB.ld +# add define "-DSPIDMA" to use DMA for SSI encoder, in that case IF1 (USART3) would be interrupt-driven! DEFINES := -DUSB1_16 include ../makefile.f3 diff --git a/F3:F303/InterfaceBoard/Readme.md b/F3:F303/InterfaceBoard/Readme.md index 1a43a71..0d747be 100644 --- a/F3:F303/InterfaceBoard/Readme.md +++ b/F3:F303/InterfaceBoard/Readme.md @@ -104,7 +104,7 @@ Interfaces: DMA1 channels: -- Ch2: USART3_Tx +- Ch2: USART3_Tx or SPI1_Rx - Ch3: USART3_Rx - Ch4: USART1_Tx - Ch5: USART1_Rx diff --git a/F3:F303/InterfaceBoard/hardware.c b/F3:F303/InterfaceBoard/hardware.c index e6c2623..b00ad51 100644 --- a/F3:F303/InterfaceBoard/hardware.c +++ b/F3:F303/InterfaceBoard/hardware.c @@ -22,7 +22,7 @@ uint8_t Config_mode = 0; static inline void gpio_setup(){ RCC->AHBENR |= RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_GPIOCEN | RCC_AHBENR_GPIODEN - | RCC_AHBENR_DMA1EN | RCC_AHBENR_DMA2EN; + | RCC_AHBENR_DMA1EN | RCC_AHBENR_DMA2EN | RCC_APB2ENR_SPI1EN; RCC->APB1ENR |= RCC_APB1ENR_CANEN | RCC_APB1ENR_USART2EN | RCC_APB1ENR_USART3EN | RCC_APB1ENR_UART4EN | RCC_APB1ENR_UART5EN; RCC->APB2ENR |= RCC_APB2ENR_USART1EN; diff --git a/F3:F303/InterfaceBoard/main.c b/F3:F303/InterfaceBoard/main.c index 89447ad..a102909 100644 --- a/F3:F303/InterfaceBoard/main.c +++ b/F3:F303/InterfaceBoard/main.c @@ -22,6 +22,7 @@ #include "flash.h" #include "hardware.h" #include "proto.h" +#include "spi.h" #include "strfunc.h" #include "usart.h" #include "usb_dev.h" @@ -48,6 +49,7 @@ int main(void){ USBPU_OFF(); USB_setup(); CAN_setup(the_conf.CANspeed); + spi_setup(); //uint32_t ctr = Tms; //usb_LineCoding lc = {9600, 0, 0, 8}; //for(int i = 0; i < 5; ++i) usart_config(i, &lc); // configure all U[S]ARTs for default data @@ -63,13 +65,21 @@ int main(void){ int l = USB_receive(i, (uint8_t*)inbuff, MAXSTRLEN); if(l) USB_send(i, (uint8_t*)inbuff, l); }*/ - if(CDCready[ICAN]){ + if(CDCready[ICAN]){ // process CAN bus int l = USB_receivestr(ICAN, inbuff, MAXSTRLEN); if(l < 0) USB_sendstr(ICAN, "ERROR: USB buffer overflow or string was too long\n"); else if(l) CANcmd_parser(inbuff); canproto_process(); } - + if(CDCready[ISPI]){ // process encoder + if(USB_rcvlen(ISPI)){ // new data in USB - ask for new encoder data + if(spi_start_enc()) USB_receive(ISPI, (uint8_t*)inbuff, MAXSTRLEN); // clear incoming data + } + uint32_t val; + if(spi_read_enc(&val)){ + USB_sendstr(ISPI, u2str(val)); + } + } if(Config_mode && CDCready[ICFG]){ /*if(Tms - ctr > 4999){ ctr = Tms; diff --git a/F3:F303/InterfaceBoard/multiiface.bin b/F3:F303/InterfaceBoard/multiiface.bin index 3ac4516b644cf3248a17ce57eab5d101dbd82267..a55eb4c3e09e1052bc637c7b2325fe90975d4790 100755 GIT binary patch delta 7185 zcma)A3wTq-ww}F{rfF%RrBKqeh25q=AqCPFO55-Vr44O%q2;B#O&>r)3znA_BBb1l zfQrg@Mh{9+(dz@zD@ee@rD#!)&%?c@;sYq26I6U19~&;5>}2nq+%=Ol@FDknC*SvH z_N=vLtu-@i)~vlRUSJOVjd7y`hc~5N$>5)x_@t^2?nkGCj)=^C%oGm zxnU!);KnnR?FTdN8-&~HEAbiT3_DZC``BFezQy=0_G9*m#rQ$hA+<{QLd2!&3V85{ zc&qxaqmRH?HA39!_s1aAj4U5Q-v{V;crlWp)h$6<5a3Kp@Q%01k79hIQcC$F75tC5RqiWt9_{`j4+3$O zpjIKH%F9vOH}U{VV<|0*($33?l*Uk+j?zAn<9L*-w{SngJbv#{f?N4lF?i?Ll~W6>ti02H*vJ3-}oz0#cS@HolVGD&y+-Q*7Q+k49V0 zu+>X(MZy$yoN!L`Y)?4AvJZsth@`wkIS_H;u>hWzl$Uoo+T9XBh9aNj2pbd5N9J)Z z%4rMW{Ym-O?r8T;5KQtV(`g-#(q;x+&I?CXynY?a>#RCDxl)*#V=2;Z2OI#L23%Z< z6O%djcDZjWb_S3Sbw^gCE<#Oz+(Dt07 zhFhYBRe{z^UCvCS_WYkH{jMn8FWP~=Q#6>`SFyqo(B^Vvwj*Of&ucYtIj{wMU@tIr zR#r%lIWsLf_`HZePF|EgAliLNOu6K8FvUc;LB{3%C%M(aWihgfTg2~teawkq1{usv z8NM5?^D);4dQUpdEuAR-N-5K?a=K_LAg*P@7;_6#Y;H2QsEl8qC(B`OK}K!Qayp^c zqjqYs?BPo{0)g6g~Y1a7?{gNDxa~SmBFc-#Rm5e~?rO zN|?B<5*`ni(oGUzQ_wO9ApnWP0%#`z9Dv<`QvmNWyfsCfw<0<;6q@Th(aH)ZgD0Bf zuOz`1kzS9~-h8sv)k?PL2sJe;D*s)`3}NNDj_%f;eT8zSMLFj~_~X2KE@ju9egM>=9_|VTn;lhkpfPXf)iUMv8lXOYS~wj*0Y;x zkV0Yq%aY1Ubi5bSA%r5Uuq!mqXI|>`Tu;AC`{_11;F~DR70UIQom*_ULVNx`%K0M7 zSrZxz9Gx}n=f!&|=c5qmv%=#s1E-_13qttJ!10OCM!RJpoS0^tel{RB#$Oo(PKyu$ zKLt-T23K{h+E>APUCwG-n!TE8Z4OmI8XIN<_K$*~C9|%I4Q`7{YZcr&c!Ya_QVPp9JjSk9?x%KZ6&HV29F!|L(=5oS_C_{z znxgW#DSwi(mA0kIT98vmyh_2>W+Q8z_fUmd7}mNu2{I zbF;LXG6yP{OV_h%1y4#J%3Q;X(=)QZmuq4JBC0B+c~ts>jQ4=_85zHtuAlUlJf6z+ zqO{7zj)|UQ z`6}VtDD^%Gb=T9(mjnmlL^61C8t@_Dvqt>1u8rL%;gpOL_pF%0P0}!GY@^iWSo{E4 zG)IirA|ZpcKGnz3q>3cTb<%Nm36Z%YCbJNzOtG{+=#n<=tN8J3WXpaEhWxwb6ZS3# zGQQS>x>0vZv?TC>FG(iw4w;apS_^FxEZ^~eqjw|O6=Y2Cwma0qX*dCT>n4Y~nh~DE z*E7a358~naam+eAUq5n?Px?SiV!jlU3XyU2R~lG@7Xx^Yek_|O;nR8@`%1ubL7&dB z&xSo$Gp8_F4+I#4t1;b|!uLjN9F2Ei4H3~h9)go|P=pSg?3zXXXn!%E~n6?v-Zf5cKJ zBXq{-?~7JSe@8q4^haa#lj1Z=e?uho9nrNd#(PzqM0p2AbCkC}#(O#eZc1XXM8qk> zPE1pSW8(o9KsBHqz%htxhBlvU0moVl%*v`)9{BCQ$#!%cdkE(K2EWL8yyiHcHl6n* zbMZ{VdYj%}C+wNN4rk{)oLq0~H+^p7EWQq?Gx48ts+h@G$yuJ3N9nn|0q8k=u5F(^ z7jMkXiP!TSRE9eIRIV|rKhNaq+fa7_1jABM?P{9=p^?H`R4GG|$CulznvhZeZarsH zTQV4g)DDEYcR&hP2}vp~#6|oSttu006=>Nsdk0)!zn<;jJMg9vIqr`G?U46=gmbU> z?+GDcPl)(jCv-IKYgi9))q4~fk?>guBV@>7|0jXF`Nf+EEgQ5BQq^7SSVzthE0~lI zL=Ga0gUC`}SOJHF6<(CJz9@xC>#QOFNzigtT*`M+Ervy24G5lu7(vD)FA`LcdXO>x zCgp^GS~f%WN5Td;KP1r2Rljq1^ig|^-M+=L4 zkCLcjh078Lo6QQBq+%Q4rBy~Isp=_)2w{aXxrnwCWFx+RWSM)f{DGJS6U(9#(^Fou zT={*3GWD9}aD=9k$$}8Cwgx{CbudB)Bc@(69fqe=qWLPM8`3@~4gVf>8vtYzJAN%e zbo*K_vgCj#!B%qFh--srtJIx^11CYi}T(N{nv_eheX_oykhGI`Qu>K`ZJZ}SV>36R>@;x4F>nPQiH zv%?IP_HVtBDM&#HsFGcBXpDdUDut?>FC|7J2?@hurfpHvUkCe=+4ki~OD6glv>Y6( zgU}uWbR6GBQ-}+aUz68`A03s-JrfoiBquW7=?ywbr9an8EY_c!oFh6_!hR8-9;Mec zhay5#ypoe7!g4QR?h*0TQFiy4U@{cX8h{$W0!T3($47$U%^*h;Eb-?Itgjc)aXgaB zB4up50||Ly*6MQL3Z^HXPk^$O)B#UG`Gt&(SH&Zr3SMs_iJFWjdLlYh)-tzUT3ZSS zF$>bNWKW|D_3yzl2iY-qFtV6Kg3_j-ql{*(dnM7HNTu3>BAB)*k!;8cj$j<6H^&z8 zG%T7IaE>k>ahmLI2RPV!wA`9X>m~OzNORI!3mrNGcJ1a3?+utK-3$(pxs<|ON~0@N zNNIDuk)RqKG}8n3k7zPyg`A*?j?E65H?eSZS!41=WMsVzyaj80qxmj-oNpB0g+DP4 zNYn&JP+2yJe=wTze}s#g%>QzrYtxPB+Z-4|sTb%i!3ygF*ixXY_rc_T2FL)k0&Wbz zAb<{#1>gXAfJp!gpb}6ESOEC_PG*Jh!GiJq$u^NXII`{drvi>ug>llDc6ZZQq}>E~ zH;QdHJ@?UWZFhpqLx89L1=(B2-rQe07P+-yf2mU9s}sVekpD7GhKyIwkM-&K0$<3# zHKgP7ePREOP#*jzD%IkfpbP>H`N;C=dU7M`%KE35wVVS7$k#7-^ z6VN5Xi7@oVZxZV63*qJ!o=3)ZFzgBir*-hsXW{hb1v8iK<|P*8G61(y}cj!kZ7AOj8~=E zwQyU-+ooSTF?X&#p5Atv>X83$P!0`%+KhY?K_?)suxBcS~T)@NNZ71?t9oN$ZDX+_(4cF&y=erzP&}w?Jz|Gy@=BXeua8Q~C z9cE{myE3u;)1&$}Gnh9w5EFknpA06FYzAtctbPK_mY5^iPUY3`dWXxQw==L4kq;%P zo6MBVx}LVkGIeVlvH-Tj?2~}raSR=fr3D3a_uh&EB;+!Tv=9;uK0_Ay_grV)W}F#orH4F3;5b1)ii3URIv3IR=m4hVbt4MVjsKcr1i}E?-vL z8cMBJ{B=NZhe%E~(M-G_W>>!wUK0Qgzy?4EU_ZbPlQ}`!frx9(g4M~phQ`AU^4UuK zNAuAUzbINz=v5Ryq6+(JXQFa9h?C*sO1x&$j-h)M4Tx?A(L)NceY2>};TbqNiP8KZ zD}J4V^QIIqRe1K4$(kcT@X7eGDV3uig2yiTfUi&W_Ne+&2b7NBQ7d?8hv)kon4P*p zGaba&%XrPyf~*7K6AfK(qfPnBys8)4!QN5e$uJP8lkpo<8#RBI6o00Shgyb?AoJ|g z{QOOt&%iU8e>>m@2X3^igJSY?i&=9wjD1GJ>C@(Dro-cU39p&9EQ2`N=TwRlX$t^! zxaab;I)<`|C9*uk8qrGFt)7|F`!USBcwuEGa~yB1e3)5-RaI5#RWsnzGGHa(tA_Qj1_KU2dkgHN6aTfUnc0D-TML=hc%yX~`+N)jqt(WiEBI^cs^kM; zN(c4M&n%Pzc;SputXIO@XG~(6@Y^${4XFr8o8oGM&S|27i`>f2l1uqdzs;QVND^EgdeKe!f-gjW`zF<@c%Gwu#IHnZ1_Q2`RIq`#Xe~ZW3={2 zj>YYqS!JAjj(Kj5Xb@2M=e0=tzktCr;Y0jP{HrZ5b4^J0KONeoZZrCB@Sqd_N9gNNkwPKNtKXN`PE{h7tD%}QrJ$M4O`VXFi9hgtdA zivMc39nvG*{TGk{`CRaIpwHCiWa%-vfB) z>=LFwoO&*Xb%&fm*GbNP;uOe(3Sp8!S9c~CysktH8zFSwU^6hFRTX{KEcks2II zKXof`e?h+eAW1ODle{oFq5pW!!WEf{O2(Lq#uS-6`Hd#FXnmV=Y!jDXJE3e;IXAby zhFiaU!^SqQjt4z`yotrY+u&Ti{O*k#5W;sfUtvp%aLw|}Y%-{F=Cm=*>zwy2UxU!b z^$qJbP<@4^TULZetswl@R}99BR;03p zggzL*zan*LkqPvUFP*@RnZnIm0G`~?TU=~{5hI39DE$9LN(w#KS4?I5TOd5^0S-WA z3$AcJ!d_hF`P4a(Vb3*rzFSoe%ZhVa(Ty~UM;4gJ{{aw-s_p;) delta 6511 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 a%$v|~)yAYLT>i~C){V23BpWJWY5xmQXs@LJ diff --git a/F3:F303/InterfaceBoard/multiiface.creator.user b/F3:F303/InterfaceBoard/multiiface.creator.user index 0edb3ce..d728581 100644 --- a/F3:F303/InterfaceBoard/multiiface.creator.user +++ b/F3:F303/InterfaceBoard/multiiface.creator.user @@ -1,6 +1,6 @@ - + EnvironmentId diff --git a/F3:F303/InterfaceBoard/multiiface.files b/F3:F303/InterfaceBoard/multiiface.files index 66efa66..9b0bdaf 100644 --- a/F3:F303/InterfaceBoard/multiiface.files +++ b/F3:F303/InterfaceBoard/multiiface.files @@ -13,6 +13,8 @@ proto.c proto.h ringbuffer.c ringbuffer.h +spi.c +spi.h strfunc.c strfunc.h usart.c diff --git a/F3:F303/InterfaceBoard/spi.c b/F3:F303/InterfaceBoard/spi.c new file mode 100644 index 0000000..23609d1 --- /dev/null +++ b/F3:F303/InterfaceBoard/spi.c @@ -0,0 +1,108 @@ +/* + * This file is part of the multiiface project. + * Copyright 2026 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "Debug.h" +#include "hardware.h" +#include "spi.h" + +typedef enum{ + SPI_NOTREADY, + SPI_IDLE, + SPI_READY, +#ifdef SPIDMA + SPI_BUSY +#endif +} spiStatus; + +static spiStatus spi_status = SPI_NOTREADY; +static uint32_t spidata = 0; + +#define WAITX(x) do{volatile uint32_t wctr = 0; while((x) && (++wctr < 360000)) IWDG->KR = IWDG_REFRESH; if(wctr==360000){ DBG("timeout"); return 0;}}while(0) + +// init SPI to work with and without DMA +// DMA1Channel2 - SPI1 Rx +void spi_setup(){ + SPI1->CR1 = 0; // clear EN + SPI1->CR2 = 0; + // SPI for SSI: PA5/PA6, without MOSI; suppose that clocking and GPIO OK (hardware.c) + RCC->APB2RSTR = RCC_APB2RSTR_SPI1RST; // reset SPI before start + RCC->APB2RSTR = 0; // clear reset + SPI1->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_RXONLY; // software slave management (without hardware NSS pin); RX only +#ifdef SPIDMA + // setup SPI DMA + SPI11->CR2 = SPI_CR2_RXDMAEN; + // Rx + DMA1_Channel2->CPAR = (uint32_t)&(SPI1->DR); + DMA1_Channel2->CCR = DMA_CCR_MINC | DMA_CCR_TCIE | DMA_CCR_TEIE; // mem inc, hw->mem, Rx complete and error interrupt + NVIC_EnableIRQ(DMA1_Channel2_IRQn); // enable Rx interrupt +#endif + // Master, baudrate = 0b110 - fpclk/128 (562.5 kHz) + SPI1->CR1 |= SPI_CR1_MSTR | SPI_CR1_BR_2 | SPI_CR1_BR_1; + // DS=8bit; RXNE generates after 8bit of data in FIFO; + SPI1->CR2 |= SPI_CR2_FRXTH | SPI_CR2_DS_2|SPI_CR2_DS_1|SPI_CR2_DS_0; + spi_status = SPI_IDLE; + DBG("SPI setup OK"); +} + +// return TRUE if data ready and change `encval` +int spi_read_enc(uint32_t *encval){ + if(spi_status != SPI_READY) return FALSE; + spi_status = SPI_IDLE; +#ifndef SPIDMA + // clear SPI Rx FIFO + for(int i = 0; i < 4; ++i) (void) SPI1->DR; + SPI1->CR1 |= SPI_CR1_SPE; + uint8_t *data = (uint8_t*) &spidata; + for(uint32_t x = 0; x < ENCODERBYTES; ++x){ + if(x == ENCODERBYTES - 1) SPI1->CR1 &= ~SPI_CR1_RXONLY; // clear RXonly bit to stop CLK generation after next byte + WAITX(!(SPI1->SR & SPI_SR_RXNE)); + data[x] = *((volatile uint8_t*)&SPI1->DR); + } + SPI1->CR1 &= ~SPI_CR1_SPE; + SPI1->CR1 |= SPI_CR1_RXONLY; // and return RXonly bit +#endif + if(encval) *encval = spidata; + return TRUE; +} + +#ifdef SPIDMA +// start encoder reading over DMA +// @return FALSE if SPI is busy +int spi_start_enc(){ + if(spi_status == SPI_BUSY || spi_status == SPI_NOTREADY) return FALSE; + if(SPI1->SR & SPI_SR_BSY) return FALSE; + DMA1_Channel2->CMAR = (uint32_t) &spidata; + DMA1_Channel2->CNDTR = 4; + DMA1_Channel2->CCR |= DMA_CCR_EN; + SPI1->CR1 |= SPI_CR1_SPE; + spi_status = SPI_BUSY; + return TRUE; +} + +// SSI got fresh data +void dma1_channel2_isr(){ + SPI1->CR1 &= ~SPI_CR1_SPE; + spi_status = SPI_READY; // ready independent on errors or Rx ready +} +#else +int spi_start_enc(){ // simple stub + if(spi_status == SPI_NOTREADY) return FALSE; + spi_status = SPI_READY; // user asks to read data + return TRUE; +} +#endif diff --git a/F3:F303/InterfaceBoard/spi.h b/F3:F303/InterfaceBoard/spi.h new file mode 100644 index 0000000..72d78a7 --- /dev/null +++ b/F3:F303/InterfaceBoard/spi.h @@ -0,0 +1,27 @@ +/* + * This file is part of the multiiface project. + * Copyright 2026 Edward V. Emelianov . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include + +// amount of bytes to read from encoder +#define ENCODERBYTES 4 + +void spi_setup(); +int spi_start_enc(); +int spi_read_enc(uint32_t *encval); diff --git a/F3:F303/InterfaceBoard/usart.c b/F3:F303/InterfaceBoard/usart.c index c1a247a..6226a8b 100644 --- a/F3:F303/InterfaceBoard/usart.c +++ b/F3:F303/InterfaceBoard/usart.c @@ -52,7 +52,11 @@ typedef struct { // IF6[5]: (CAN) // IF7[6]: (SPI) static const USART_Config UC[USARTSNO] = { +#ifdef SPIDMA + [0] = {.instance = USART3, .pclk_freq = 36000000, .UIRQn = USART3_IRQn, .dma_controller = NULL, .DEport = GPIOB, .DEpin = 1<<14 }, +#else [0] = {.instance = USART3, .pclk_freq = 36000000, .UIRQn = USART3_IRQn, .DIRQn = DMA1_Channel2_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel3, .dma_tx_channel = DMA1_Channel2, .TTCflag = DMA_ISR_TCIF2, .DEport = GPIOB, .DEpin = 1<<14 }, +#endif [1] = {.instance = USART1, .pclk_freq = 72000000, .UIRQn = USART1_IRQn, .DIRQn = DMA1_Channel4_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel5, .dma_tx_channel = DMA1_Channel4, .TTCflag = DMA_ISR_TCIF4, .DEport = GPIOB, .DEpin = 1<<0 }, [2] = {.instance = USART2, .pclk_freq = 36000000, .UIRQn = USART2_IRQn, .DIRQn = DMA1_Channel7_IRQn, .dma_controller = DMA1, .dma_rx_channel = DMA1_Channel6, .dma_tx_channel = DMA1_Channel7, .TTCflag = DMA_ISR_TCIF7, .DEport = GPIOA, .DEpin = 1<<1 }, [3] = {.instance = UART4, .pclk_freq = 36000000, .UIRQn = UART4_IRQn, .DIRQn = DMA2_Channel5_IRQn, .dma_controller = DMA2, .dma_rx_channel = DMA2_Channel3, .dma_tx_channel = DMA2_Channel5, .TTCflag = DMA_ISR_TCIF5 }, @@ -410,7 +414,9 @@ void uart4_exti34_isr(){ usart_isr(3); } void uart5_exti35_isr(){ usart_isr(4); } // DMA Tx interrupts (to arm ready flag) +#ifndef SPIDMA void dma1_channel2_isr(){ TXrdy[0] = 1; DMA1->IFCR = DMA_IFCR_CTCIF2; } +#endif void dma1_channel4_isr(){ TXrdy[1] = 1; DMA1->IFCR = DMA_IFCR_CTCIF4; } void dma1_channel7_isr(){ TXrdy[2] = 1; DMA1->IFCR = DMA_IFCR_CTCIF7; } void dma2_channel5_isr(){ TXrdy[3] = 1; DMA2->IFCR = DMA_IFCR_CTCIF5; } diff --git a/F3:F303/InterfaceBoard/usb_dev.c b/F3:F303/InterfaceBoard/usb_dev.c index 0bc3cd5..3fa8ab8 100644 --- a/F3:F303/InterfaceBoard/usb_dev.c +++ b/F3:F303/InterfaceBoard/usb_dev.c @@ -303,6 +303,10 @@ int USB_sendstr(uint8_t ifno, const char *string){ return USB_send(ifno, (const uint8_t*)string, len); } +int USB_rcvlen(uint8_t ifno){ + return RB_datalen((ringbuffer*)&rbin[ifno]); +} + /** * @brief USB_receive - get binary data from receiving ring-buffer * @param buf (i) - buffer for received data @@ -336,7 +340,7 @@ int USB_receivestr(uint8_t ifno, char *buf, int len){ } int l = RB_readto((ringbuffer*)&rbin[ifno], '\n', (uint8_t*)buf, len); if(l < 1){ - if(rbin[ifno].length == RB_datalen((ringbuffer*)&rbin[ifno])){ // buffer is full but no '\n' found + if(rbin[ifno].length >= RB_datalen((ringbuffer*)&rbin[ifno]) - 1){ // buffer is full but no '\n' found while(1 != RB_clearbuf((ringbuffer*)&rbin[ifno])); return -1; } diff --git a/F3:F303/InterfaceBoard/usb_dev.h b/F3:F303/InterfaceBoard/usb_dev.h index 303d30e..1b50818 100644 --- a/F3:F303/InterfaceBoard/usb_dev.h +++ b/F3:F303/InterfaceBoard/usb_dev.h @@ -61,6 +61,7 @@ int USB_send(uint8_t ifno, const uint8_t *buf, int len); //int USB_adddata(uint8_t ifno, const uint8_t *buf, int len); int USB_putbyte(uint8_t ifno, uint8_t byte); int USB_sendstr(uint8_t ifno, const char *string); +int USB_rcvlen(uint8_t ifno); int USB_receive(uint8_t ifno, uint8_t *buf, int len); int USB_receivestr(uint8_t ifno, char *buf, int len); uint8_t IFconfig(uint8_t ifno, usb_LineCoding *l); diff --git a/F3:F303/InterfaceBoard/version.inc b/F3:F303/InterfaceBoard/version.inc index 30fb985..9542a9b 100644 --- a/F3:F303/InterfaceBoard/version.inc +++ b/F3:F303/InterfaceBoard/version.inc @@ -1,2 +1,2 @@ -#define BUILD_NUMBER "151" -#define BUILD_DATE "2026-02-19" +#define BUILD_NUMBER "154" +#define BUILD_DATE "2026-02-20"