Rate my code - Page 1
Forum section: electronics / general

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 25, 2020, 07:45:22 pm
content: Code:uint16_t prebufferk;uint8_t bufferk;typedef union {uint16_t prebufferk;uint8_t bufferk;} combok;uint8_t index_k;const uint8_t index_k_ref=3;extern USBD_HandleTypeDef hUsbDeviceHS;int main(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* Initialize all configured peripherals */index_k=0;MX_GPIO_Init();MX_USB_DEVICE_Init();MX_SPI2_Init();MX_TIM2_Init();/* USER CODE BEGIN 2 */bufferk=1;//reportIDbufferk=0;//modifierbufferk=0;//OEMbufferk=0;//keycode databufferk=0;//keycode databufferk=0;//keycode databufferk=0;//keycode databufferk=0;//keycode data/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE */if(LL_SPI_IsActiveFlag_RXNE(SPI2)){if(LL_GPIO_IsInputPinSet(f7i1_GPIO_Port, f7i1_Pin) && index_k !=index_k_ref) // If pin is high and index threshhold not reached{prebufferk=SPI2->DR;index_k ++;}else{}}if(index_k==index_k_ref){USBD_HID_SendReport(&hUsbDeviceHS, bufferk, 8);}/* USER CODE BEGIN 3 */}/* USER CODE END 3 */}Code:uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev,uint8_t *report,uint16_t len){USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef *)pdev->pClassData;if (pdev->dev_state == USBD_STATE_CONFIGURED){if (hhid->state == HID_IDLE){hhid->state = HID_BUSY;USBD_LL_Transmit(pdev,HID_EPIN_ADDR,report,len);index_k=0; // This part does not compile.}}return USBD_OK;}So the goal is to transfer a SPI buffer into some ram and once the accompanying buffer is full, write to USB endpoint.One problem I face face is that index_k in the HID_Sendreport function is not recognized, cant remember if I should put index_k extern and inside usbd_hid.c ?

author: ataradov
author_rank: Super Contributor
timestamp: February 25, 2020, 08:03:53 pm
content: What is there to "rate"? It is a trivial amount of code.If you are asking about part that does not compile, then having the test of the error would be helpful.What is the relative location of those two pieces of code?EDIT based on the update: It must be declared for real in one file and declared extern in all other files that use it. Or in a common header file.

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 25, 2020, 08:06:57 pm
content: Quote from: ataradov on February 25, 2020, 08:03:53 pmAll compiled untill I decide to modify the HID_Sendreport and add index_k=0; at the end.Static extern int8_t index_k;inside usbd.c ??Missing an #include somewhere.

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 25, 2020, 08:11:38 pm
content: What about my use of a union?Is this legit?I just wanna transfer the SPI register, wich works with 16bit SPI setup to minimize downtime duh.Then pass this data to function, wich takes only bytes.

author: ataradov
author_rank: Super Contributor
timestamp: February 25, 2020, 09:08:34 pm
content: The union itself is fine, but I don't understand what you are trying to do after that. This code only declares a type, but never instantiate a variable of this type.And if all you need is pass the array of uint16_t as an array of bytes, you can simply cast.It can't be static and extern at the same time. No need for static in this case.

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 25, 2020, 09:41:52 pm
content: I messed up the constants values, it should be +1 offset from those numbers.I just wanna write computer as keyboard via SPI bridgeCompiles now, zero erros, zero warnings.I kinda needed help because I only got 1 st-link.

author: AG6QR
author_rank: Frequent Contributor
timestamp: February 26, 2020, 12:12:59 am
content: Quote from: lawrence11 on February 25, 2020, 08:11:38 pmWhen you make a union of different sized integer types, beware of bugs regarding big-endian vs. little-endian. If you only want your code to run on one architecture, you can possibly get away with hacking it until it works, and not worry so much. If you want it to be portable, you should write two versions of the critical portions of the code, and use #ifdef to select the proper version based on the endian-ness of the processor.

author: TomS_
author_rank: Frequent Contributor
timestamp: February 26, 2020, 08:56:08 am
content: Style wise, you have an inconsistent use of spaces around operators and what not.this=that vs this = thatthis ++while (1)if(...)Based on that, low rating.

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 26, 2020, 10:24:14 am
content: Thats because, theres was like a ton of other stuff that I deleted.Not gonna put effort beyond what is readable.

author: thinkfat
author_rank: Unknown
timestamp: February 26, 2020, 10:26:40 am
content: Quote from: TomS_ on February 26, 2020, 08:56:08 amYep, together with comments leftover from copying some code template which don't give any hint what the code is doing,the inconsistent indentation, the mix of C and C++ comment style, not using initializers for seeding bufferk[], and on top if it,IF IS NOT A FUNCTION CALL!!!111 out of 5, and the "1" is for spending the effort of showing up and asking for comments.

author: mariush
author_rank: Super Contributor
timestamp: February 26, 2020, 01:32:21 pm
content: nothing jumping outi hate brackets on single lines ex}else{just type } else {alsoCode:if(LL_GPIO_IsInputPinSet(f7i1_GPIO_Port, f7i1_Pin) && index_k !=index_k_ref) // If pin is high and index threshhold not reached{prebufferk=SPI2->DR;index_k ++;}else{}could be rewritten asCode:if(LL_GPIO_IsInputPinSet(f7i1_GPIO_Port, f7i1_Pin) && index_k != index_k_ref) {// -comment on new line inside the brackets , indentation makes it obvious where the code belongs// If pin is high and index threshhold not reachedprebufferk=SPI2->DR;index_k ++;} else {// the else part}

author: donotdespisethesnake
author_rank: Super Contributor
timestamp: February 26, 2020, 02:23:27 pm
content: Quote from: thinkfat on February 26, 2020, 10:26:40 amThat is true, but why do you point that out?

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 26, 2020, 02:57:43 pm
content: Quote from: lawrence11 on February 26, 2020, 10:24:14 amThen don't ask people to rate your code.(Oh and don't overestimate the readability of a given piece of code, see below.)Consistency is a key point for readability and maintenance, much more so than style itself, which can have almost as many variants as there are developers (and it often leads to completely fruitlesss discussions). So pick a style and use it consistently. Lack of consistence just looks sloppy and kills readability.Other than that, you're using some global variables like index_k which IMO shouldn't be global variables. Keep that local. Pass it to other functions as a parameter if needed.Apart from specific cases, favor parameters to functions instead of relying on a bunch of global variables which will just make your code look like spaghetti and will make your functions non-reentrant.

author: thinkfat
author_rank: Unknown
timestamp: February 26, 2020, 03:58:20 pm
content: Quote from: donotdespisethesnake on February 26, 2020, 02:23:27 pmRight:Code:if (expression)WRONG:Code:if(expression)

author: Siwastaja
author_rank: Super Contributor
timestamp: February 26, 2020, 04:16:30 pm
content: Quote from: thinkfat on February 26, 2020, 03:58:20 pmYou must be new to programming. Don't worry, most of the too-simplistic-to-be-meaningful arrogance that leads to such false statements of perfectly correct code being "wrong" will go away once you have to actually work on code made by others possibly using different styles.

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 26, 2020, 05:00:14 pm
content: Quote from: SiliconWizard on February 26, 2020, 02:57:43 pmI dont understand the problem withif(LL_SPI_IsActiveFlag_RXNE(SPI2)) vs while(LL_SPI_IsActiveFlag_RXNE(SPI2))I thought the only difference was that after the loop the if doesnt check if true again.I googled these exact terms : LL_SPI_IsActiveFlag_RXNE(SPI2) , I always saw it in a while and sometimes if.If you XXXXXXX=SPI2->DR; , its cleared, then forks again, doest it always = the same time execution but if is safer for overall SW?

author: thinkfat
author_rank: Unknown
timestamp: February 26, 2020, 05:36:34 pm
content: Quote from: Siwastaja on February 26, 2020, 04:16:30 pmYou must be an EE. That's fine. Just don't try to teach me "programming".

author: AG6QR
author_rank: Frequent Contributor
timestamp: February 26, 2020, 05:50:09 pm
content: Quote from: lawrence11 on February 26, 2020, 05:00:14 pmThe difference is that an if is not a loop. A while is a loop. Thus, there is no "after the loop" with the if block.In general, comments shouldn't put much effort into explaining what your code is doing, but instead they should explain why. It is almost never appropriate to explain basic language features in comments. You can assume the programmer knows the language, or at least knows where to find a manual to fill in any gaps in language knowledge.The reason for comments is to tell someone, many years in the future, what they need to know in order to understand, debug, maintain, and enhance your code.The programmer who reads your comments might be your future self, so write them well!

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 26, 2020, 06:25:40 pm
content: Did you notice above I wrote''I thought the only difference was that after the loop the if doesnt check if true again.''All you guys do is jackoff around and complain for no reason, typical programmers.

author: NivagSwerdna
author_rank: Super Contributor
timestamp: February 26, 2020, 06:45:36 pm
content: You are brave.If I was going to be fussy...In days of old when knights roamed the land chasing damsels we might have used lint.... It probably would have said that any constants other than 0 or 1 should be #defined.I don't particularly like the buffer intialisation style but it is harmless and I don't like the inconsistent indentation around {}...... But if it works then go for it.

author: donotdespisethesnake
author_rank: Super Contributor
timestamp: February 26, 2020, 06:48:10 pm
content: Quote from: thinkfat on February 26, 2020, 03:58:20 pmThis is why code reviews are such a waste of time. People argue over complete trivia, and rarely find any real bugs.

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 26, 2020, 07:15:22 pm
content: Quote from: SiliconWizard on February 26, 2020, 02:57:43 pmHeres the thing tho, I`m a bit scared to touch these functions, messing with their parameters.So you think its worth it??

author: newbrain
author_rank: Super Contributor
timestamp: February 26, 2020, 08:18:54 pm
content: Quote from: Siwastaja on February 26, 2020, 04:16:30 pmThis.I see most of the comments focused on formatting, indentation, spaces and similar trivia. I did not have time to go through the actual code.I will simply say: use a modern editor of your choice, they all can indent code correctly; this will also help catch a number of coding mistakes.Some are better than other, but like indentation, everyone has their tastes.If you are working in a team, stick to the existing convention (even if you personally dislike it).

author: thinkfat
author_rank: Unknown
timestamp: February 26, 2020, 08:41:18 pm
content: Quote from: donotdespisethesnake on February 26, 2020, 06:48:10 pmYes, but the OP was not asking for a code review but for a "rating". My comments were in the spirit of that, on the "style". Which is sort of a useless metric, unless you're in the business of writing "safe" code that is subject to certification, requiring enforcing of certain coding standards.Though, as you progress as a software developer, you'll find it necessary to develop a certain consistency and you'll learn that it really helps to place "hints" in the code for your brain to parse it more quickly. Discerning strictly between function calls and structural and control elements is one such hint that helps you along.

author: jbee
author_rank: Newbie
timestamp: February 26, 2020, 08:50:51 pm
content: QuoteIf you're working in a bare-metal environment with no OS or threading and you know what you're doing (ie if your global sits in an interrupt, do you know when it's going to get set/read), having globals is fine. You're taught to limit the scope of objects as best as you can, but in these small microcontroller projects, sometimes having globals is more readable than following a stupid counter parameter through function calls, etc. In fact by having a global instead of passing it around, you avoid the dynamic stack memory allocation. In my small microcontroller projects, clock ticks are more valuable than following rules for the sake of following rules.All that being said, I don't think you're code is going to work because of that union. You declare combok as a union of a uint16_t and uint8_t, but you never declare a combok object. So in all those places you're setting the bufferk variable and expecting prebufferk to be sitting at the same memory location, you're wrong. Because you declared bufferk and prebufferk above the union, those are the variables you're *actually* setting. They're not tied together at all, they're just separate variables.So when you do prebufferk=SPI2->DR; you're setting that register to garbage, or 0, or however the compiler initializes globals.Sorry, I read that backwards, you're saving the DR register to prebufferk. It still stands that if you think there's a relationship between bufferk and prebufferk, there's not; but I'm not 100% sure if that's what you're trying to do.

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 26, 2020, 09:02:05 pm
content: So whats the solution?Delete them?

author: jbee
author_rank: Newbie
timestamp: February 26, 2020, 09:34:55 pm
content: Quote from: lawrence11 on February 26, 2020, 09:02:05 pmIf you're planning on using the union, then yes. But if that's all you do, it won't compile. You need to declare your union inside main likeCode:union {uint16_t prebufferk;uint8_t bufferk;} combok;Here you're defining combok as a union of those two objects. Then when you want to set/read those prebufferk/bufferk variables, you do combok.prebufferk = foo; Since prebufferk and bufferk are members of that union, you need to use the period operator to access them.From what I can tell it looks like you're trying to read a 16 bit value off the SPI data register and just echo it out of a USB interface that takes 8 bit values?What's the point of doing all thisCode:/* USER CODE BEGIN 2 */bufferk=1;//reportIDbufferk=0;//modifierbufferk=0;//OEMbufferk=0;//keycode databufferk=0;//keycode databufferk=0;//keycode databufferk=0;//keycode databufferk=0;//keycode dataIf when the first call to prebufferk=SPI2->DR; just overwrites that data?

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 26, 2020, 11:21:09 pm
content: Yes it overwrite.That data is remnant, should be all 0.Its just a SPI to USB passover.Functions that write to usb take uint_8 as parameter, while SPI read register can be read in 16 bit instructions.Thus the need to unionize, it will take the raw binary and pass it.Consideration for what it is is the job of SPI transmitter.

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 27, 2020, 12:07:25 am
content: jbee is the wise one.All you complainers overlooked a massive flaw.Frikkin just jackoff in my threads and belittle the self learnr all the time.

author: jbee
author_rank: Newbie
timestamp: February 27, 2020, 12:23:14 am
content: You can avoid the union if you just have the uint16_t data type (let's keep it prebufferk), and when you call USBD_HID_SendReport(&hUsbDeviceHS, bufferk, 8 );, you cast it to a uint8_t * like someone else pointed out earlier in the thread. Since it looks like the call takes a pointer to the data buffer and number of bytes, you could just do:Code:USBD_HID_SendReport(&hUsbDeviceHS, (uint8_t *)prebufferk, 8);Assuming the part where you're reading from the SPI register and indexing is working correctly, this should work fine. And even better:Code:USBD_HID_SendReport(&hUsbDeviceHS, (uint8_t *)prebufferk, sizeof(prebufferk));When you pass a pointer to a function, you're essentially passing the memory address of the first element in the allocated memory block. You've allocated 4 uint16_t's in memory (uint16_t prebufferk; ). Which is the same as 8 uint8_t's if you envision it in the memory stack. You can safely cast it to a uint8_t * and tell the function to read out 8 bytes.You use sizeof() so if you change the size of the prebufferk and all the calls still work; you don't have to go through everything and change the "8" to something else. And again, since prebufferk is an array of 4 uint16_t's, sizeof(prebufferk) is 2 bytes * 4 elements = 8.

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 27, 2020, 12:31:31 am
content: So the question is, what the hell is union good for anyways and does it result in the same?

author: jbee
author_rank: Newbie
timestamp: February 27, 2020, 01:05:02 am
content: I mean, what you were initially trying to do would have most likely worked (I don't like to say for sure unless I can test it), but in your case, when passing a pointer to a function that simply has a different type, a cast is what is used.I've never really sat down to think about when to use unions. I've been doing this for a while, so you just kind of know when to use a union from experience. An example is I want to read from EEPROM. My EEPROMREAD function only returns a byte, but I have a 16-bit checksum in there I want to get. so I can doCode:union {uint16_t chksum;uint8_t in;} myUnion;myUnion.in = EEPROMREAD(chksumAddress);myUnion.in = EEPROMREAD(chksumAddress + 1);Now my 16-bit checksum is in myUnion.chksum and I didn't have to do any crazy, unreadable pointer arithmetic or anything (if it's even possible, I can't even think of a way in this situation).There are much better answers here. If I attempted to explain, I would just reiterate the answers only more poorly.https://stackoverflow.com/questions/252552/why-do-we-need-c-unions

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 27, 2020, 04:06:17 pm
content: So I was probing around, to see if my transmit chip sends the voltage to the other pin, across this massive 6 layer PCB I made.I see that when GPIO is set, one MOSI is at 2 volts, just above the "legal limit" for a high value, and the SCLK is at the expected 3.3 volts.The pins in question are setup as SPI receive only.Is this worrying? I am measuring this with a multimeter with long leads, I was in voltmeter ofc.I can reset and switch it off at will, did I mess up?

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 27, 2020, 04:11:40 pm
content: Quote from: lawrence11 on February 27, 2020, 04:06:17 pmI don't know about your whole IO setup, but I think by default, if you're setting SPI receive only mode, the MOSI pin will not be driven by the SPI module and thus will be high-impedance (thus the 2V), unless you specifically set it as a GPIO output, or as an input with either pull-up or pull-down enabled.

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 27, 2020, 04:17:06 pm
content: So everything still unbroken yet?One chip is set in SPI receive, while with the other, I make those "sending pins" into regular GPIO just to test.I dont wanna send edges into long leads so I measure after the fact, I measured 2 volts and 3.27 voltson those 2 pins.This is also to confirm a change, when I order something in SW, that I indeed see a voltage lvl change on a pin, under a 200 pin BGA. I knew it was good for communicating with SWD and not blowing up.Both were setup as push pull gpio output low speed.I havent pulled the trigger yet on a scope, I have my 1984 tek at my mothers house, still dusty and in the closet, the problem is I just dont got space for it here on a table in a corner my girlfriend made for me.

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 27, 2020, 04:28:21 pm
content: Heres my quality check for measuring BGA installs, and other MCU installs.After soldering the board and everything, you can understand that damaging the BGA would basically ruin my day and week and cause immediate stress on my weak heart.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 27, 2020, 04:38:21 pm
content: Didn't realize this is a BGA. If you're certain about your IO configuration, then it may just be a matter of a bad ball connection...

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 27, 2020, 04:46:11 pm
content: seems unlikely, I measure, when it was all powered off.from VDD rail, using right multimeter polarity, 30k ohms on this pin, and many other pins have 27k-29k 30k ohms, some have 10k ohm.Anyways, I guess its good enough, 2 volts is higher than 1.888 and you need 1.888 to register high when VDD is 3.3 volts.

author: SiliconWizard
author_rank: Super Contributor
timestamp: February 27, 2020, 04:54:16 pm
content: Still looks fishy.I would write a very small test program in which you only set up ALL IOs as digital outputs, and test it this way...

author: lawrence11
author_rank: Frequent Contributor
timestamp: February 29, 2020, 12:31:37 am
content: So I'll answer my own question.I was in fact measuring wrong and causing bus contention situation.Since my board has no test points, I measure on the pin, and its difficult to measure a single pin, on the chip or on the pcb pin pad. My measurement caused the bad reading.I tried measuring on a more remote via on the underside, pressed the tip hard and twisted bad and forth for like 30 secs. behold 3.3 voltsPin next to it was set 0, it was itself a GPIO output PP.

author: donotdespisethesnake
author_rank: Super Contributor
timestamp: February 29, 2020, 02:50:59 pm
content: Quote from: thinkfat on February 26, 2020, 08:41:18 pmBeing doing software over 30 years. What I learned is that there is a lot of bullshit like this around and it makes no difference to code quality. If coders really can't tell the difference between a function call and if statement without extra help then they are just shit coders, full stop.The fact that coding standards are bullshit is proved by the fact every company has a different one. Learning to code based on the rules of one company just creates incompetent coders in my experience. So often have I reviewed code which follows the company guidelines perfectly, but is still full of bugs.There does seem to be a correlation between slavish adherence to "rules" and bad programming. I think people who lack the knowledge of good programming substitute for that by making their code "look pretty".

author: thinkfat
author_rank: Unknown
timestamp: February 29, 2020, 03:43:42 pm
content: Quote from: donotdespisethesnake on February 29, 2020, 02:50:59 pmNot developing a sense of order in your coding in such a long time is to me a sign of a sloppiness, if not a perturbed mind. And on the merit of coding rules, if you work in a team where more than a handful of developers work on the same code base, it definitely helps, no, it's a necessity to have common rules at least for style, if not for patterns as well.

author: lawrence11
author_rank: Frequent Contributor
timestamp: March 01, 2020, 05:44:48 am
content: I'm trying to not go the "global way" when mixig variables that get seen by IRQhandlers.trying to segment things and limit the scope of things.For instance, trying to make this variable spi1_tx_cnt a "static volatile".I tried volatile, static, volatile static, nothing seems to work.The xx_it.c file doesnt want nothing to do with it.What line of code should I add in main.h? If any.

author: thinkfat
author_rank: Unknown
timestamp: March 01, 2020, 08:21:36 am
content: Quote from: lawrence11 on March 01, 2020, 05:44:48 amspi1_tx_cnt can't be static because you need it in two compilation units. So it has to be global.Put the following line in main.h:Code:extern volatile uint8_t spi_tx_cnt;Some will frown over the "extern" and call it "superfluous". But it makes clear that this is a declaration, not a definition. It's one of those "style" things.

author: lawrence11
author_rank: Frequent Contributor
timestamp: March 01, 2020, 03:25:40 pm
content: Ok, so I managed to make it compile with various combinations.Wich is the best and what I want, in terms of limiting scope?

author: thinkfat
author_rank: Unknown
timestamp: March 01, 2020, 04:05:47 pm
content: First version doesn't work since both compilation units will use their own definition of the variable. They are independent, no communication will happen.Second version looks OK'ish, but you need to declare the variable in the interrupt handler file as "extern volatile". This version is OK from a isolation point of view.Third version - looks fishy. You should initialize a variable where it's defined, not where it's declared. I wonder why the compiler doesn't complain here. Maybe it's "legal" from a C point of view but it's not good style.

author: lawrence11
author_rank: Frequent Contributor
timestamp: March 01, 2020, 04:11:11 pm
content: so this here compiles.in main.cvolatile uint8_t spi1_tx_cnt=0;in xx_it.cextern volatile uint8_t spi1_tx_cnt;This the proper technique, no need static anywhere??

author: thinkfat
author_rank: Unknown
timestamp: March 01, 2020, 04:21:31 pm
content: It's the only way that works, if you want to access the same variable in two compilation units.You cannot use "static" because that will make the variable private to the compilation unit it is defined in. This is not what you want here.Note: "compilation unit": all source and header files read by one compiler invocation. Typically, each source file with its include file tree form a separate compilation unit.

author: SiliconWizard
author_rank: Super Contributor
timestamp: March 01, 2020, 04:25:06 pm
content: Quote from: lawrence11 on March 01, 2020, 04:11:11 pmThis would be right indeed.Don't use a static qualifier on declarations of variables that need to be visible across compilation units ("source files" if you wish). "static" is exactly meant for the opposite case: make some declaration invisible to any other compilation unit. To be used for declarations that are strictly confined to one compilation unit, and in this case, use it liberally. Also use it on function declarations (that again are not used outside of a given compilation unit), which is good practice.An alternative: you could make your variable static"static volatile uint8_t spi1_tx_cnt=0;"and define an "accessor" function in the same compilation unit to access it from the outside, like:uint8_t GetSPI1TxCnt(void){return spi1_tx_cnt;}Probably overkill for your example (and will add a small overhead), but this is also a common method for accessing variables outside of their compilation unit that gives a few benefits.

author: lawrence11
author_rank: Frequent Contributor
timestamp: March 01, 2020, 04:26:13 pm
content: Ok thanks, this is confusing.Static, extern, volatile. Always mixing these up.