-
Notifications
You must be signed in to change notification settings - Fork 47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
brzo_i2c_write: allow subsequent calls #13
Comments
I had this same problem, and to skirt the issue as a quick hack I did the same thing. I added a function to the library that took a register address as the first parameter, then allocated a new array that was 1 byte larger, copied the register address to the first element, then copied the rest of the data array into this new array and then called brzo_i2c_write with the new array. For read I hacked it by taking reg_addr and stuffing it into data[0] before calling the brzo_read; which is what the caller seemed to be expected to do in the first place. Though, I always knew fixing the body of the read/write code is what needed to happen. So here's a first cut with code that almost works (tries to use too many registers atm). The code for brzo_i2c_write first preloads the device address into a register called "%[r_byte_to_send]"; it then sends this byte; then if the "%[r_no_of_bytes]" counter hasn't reached 0 yet, it loads the next element from the data array into "%[r_byte_to_send]", increments the array pointer , decrements the counter, and directly jumps to "l_send_byte". You can find this code just before "l_send_stop:" (after "l_slave_ack:") ~line 225 - 235. Modifying the code here and adding a flag can optionally send the register address too. Here's my first take on it and it's almost working; like I said I ran out of registers to directly map the register address and I'm not sure how to look it up from the stack; and a little bit of modification to change the r_repeated register into a bitfield that tracks multiple boolean flags. Here's some psuedo code of the basic idea:
After the first time through the code, "%[r_send_addr]" will be 0 and it will jump over the register address load/send and behave just like it has before from then on. Here is the code snippet: add this 6 line section above the code that loads the data array.
Here's what the whole section looks like:
Now for the rest of the housekeeping. In the .C file add "_internal" to the original function and add two new parameters for "boolean send_addr" and "uint8_t reg_addr". Then add two new functions, one to provide the original write, and the other to take a register address. The final form will look something like this:
Like I said, as written, it requires too many registers; but it's really close. Mike |
Before rushing to (my "other") work... and being heavily occupied by it the last weeks, I just want to thank both of you for your (detailied) comments/thoughts. I should be able to spend some time on the weeknd on this issue. |
Well, I can see your point. In contrast, have a look for instance at the i2c ibrary of DSScircuits. You will find many i2c write methods, for instance I didn't want to go the DSS or wire library way with half a dozen of overloaded methods. Like send a register and one byte, or send only one byte, or two, or a register alone, or... So, coming back to the EEPROM. Now, if would like to do a page write to an EEPROM, you need to transmit: START, Control byte (aka i2c slave address of the EEPROM), Address high byte, Address low byte, Data byte 0, ..., 31, STOP. (btw: The wire library uses a fixed buffer size of 32 bytes.. So, TWI will just copy everything you want to send the |
Well, actually idea of this change is to allow to send to i2c slave any data from any "buffers" using
This appoach will allow to send multiple buffers to i2c slave and slave will see all that buffers as one large buffer. |
Primarily that variables in the code are typically stored with the data to be read/written in data arrays and the register addresses and device addresses stored separately in #defines or other const expressions. So typically I have multiple data array variables, and a mixture of immediate values and variables for device and register addresses: Given this, and this pattern is very typical, there are few options to prepend regAddr in the data[0] location of either array without doing a lot of memory copying or clobbering actual data. As for @valkuc's comment; I haven't written to EEPROM's but I think his case is already taken care of with the restart flag isn't it?
Why doesn't that do what he wants? It looks like I misread the initial post and am going to open a separate case for what I'm talking about which is more about mixing reads and writes and providing an optional function to send the register address separately from the address of the data buffer. Thanks |
@MikeFair, good explanation. Yes, actually main idea of all this is to allow streaming of data. But... I had some time to think about that and I looks like @pasko-zh is actually right to not implement that. The problem that can occur here is that at high speeds (say > 400KHz) subsequent calls to UPD. |
@valkuc : By "setup write" do you mean
If so, then you would like to have an additional parameter which allows to control that behaviour, i.e. something like OK, really misleading names for the parameters now, but I think you got the point 😄 |
By "Setup Write" I mean what the Saleae Logic analizer shows me :) Yes, I guess that is exactly START command and i2c address. The same is for read command, but then Logic analizer shows "Setup Read". |
@MikeFair : Probably you do mean something different than @valkuc. I certainly see your points, of course. However in the particular code you presented, why not use |
|
OK, thanks for the pic; it is START and slave address. Glad to hear that the library works for you :) Let me know about the necessity of this additional parameter. |
Well, if it's not hard to implement it, let's try. Then I will compare signals with logic analizer and will see. |
@valkuc I'll let @pasko-zh be the final word, but I agree with those extra delays between function calls being precisely why those starts are likely required. FWIW, I added a similar flag in the code I posted in #15 you could look at. In that case it was to send an extra byte (the register address); but you could use the basic idea of testing a ctrl_flags bit and jumping based on whether or not the bitflag is set/clear. Instead of hoping returning back to the loop was fast enough, I could see myself trying to use hardware line interrupts, timer interrupts, or some other technique to let the library keep control of sending the clock pulses (aka the i2c function loop is still running) and feeding it a stream of buffer address pointers and lengths. So instead of calling the loop with the data pointer and length, I either give it a function callback that sets the next buffer address and length and returns a 1 or 0 to inform the loop whether or not it succeeded (or setting the length to 0 means "no work to do") or give it the address of a couple global variables where the new addresses and lengths get placed. It's an interesting idea, to provide the i2c routines with a mechanism to keep the clock pulses going while getting fed new sources/targets of data to send/fill... |
I'm not very well understand assembler. To be clear, last time I was trying to write something on it - that was on ZX-Spectrum :) But, I definetely sure that introducing any mechanisms to "keep-alive" clock pulses will be total overkill for this lib. That is redundant in my opinion. I think that it's better to:
|
One thing that makes library hard to use for EEPROM write operations.
Write operation to EEPROM is made by two steps: first, send address; second, send data to write. Address and Data must sent as single one array. The tricky part here is that if I will use two separate calls to brzo_i2c_write I will have additional "Setup write" before address and data - and this is error. Address and Data must be sent one after another, so imagine that I have next function prototype to write data to EEPROM:
bool at24c_write(uint16_t addr, uint8_t* data, uint8_t len)
I can't write body like that because in this case I will have extra "Setup write" between address and data transmission:
To overrun this I need to malloc temporary array with size of data + 2, copy first two bytes of address into it, then copy data and after that send it in one brzo_i2c_write call. I guess this looks like redundant memory allocation:
Here is some ideas:
brzo_i2c_write
function to control send or not to send device address.The text was updated successfully, but these errors were encountered: