Hi to you all,In my current project I need to send over a serial bus an array of integers:
The driver I'm using (actually USB CDC VCOM from NXP, which is embedded in LPCOpen) takes pointer to unit8 and does a bulk transfer using DMA. I can output long strings, no problem. But of course I need to output data and so 32 bit integers.
Here's the function I'm trying to call:
/** \fn uint32_t WriteEP(USBD_HANDLE_T hUsb, uint32_t EPNum, uint8_t *pData, uint32_t cnt) * Function to write data to be sent on the requested endpoint. * * This function is called by USB stack and the application layer to send data * on the requested endpoint. * * \param[in] hUsb Handle to the USB device stack. * \param[in] EPNum Endpoint number as per USB specification. * ie. An EP1_IN is represented by 0x81 number. * \param[in] pData Pointer to the data buffer from where data is to be copied. * \param[in] cnt Number of bytes to write. * \return Returns the number of bytes written. */ uint32_t (*WriteEP)(USBD_HANDLE_T hUsb, uint32_t EPNum, uint8_t *pData, uint32_t cnt);
That's exactly the rotation it does. Actually consider that you don't need UXTAB since you're never going to add a value and use UXTB instead.
UXTB r2, r1, #0
UXTB r3, r1, #8
UXTB r4, r1, #16
UXTB r5, r1, #24
r2,r3,r4,r5 will contain 0x12, 0x34, 0x56, 0x78 (assuming it was a little endian 32-bit value). It's the instruction that powers ((X >> N) & 0xFF) for multiplies of 8-bit shifts. Actually UXTB (without the add) does the same thing. The 16-bit version though does it twice:
UXTAB16 r3, r0, r1, #0
UXTAB16 r5, r0, r1, #8
.. r3 and r5 will contain 0x00560012 and 0x00780034 (or the other way around. I'm having endian problems in my head). You can rotate them so that r4 and r2 will contain 0x00120056 and 0x00340078. STRB will just store bits [7:0] of the register to memory.
Anyway if you can do the UXTAB16 version, then you can also do something like:
UXTAB16 r3, r1, r0, #0
UXTAB16 r5, r1, r0, #8
STRB r3, [r0], #1
STRB r5, [r0], #1
ROR r3, r3, #16
ROR r5, r5, #16
STRB r3, [..]
STRB r5, [...]
Although the Cortex-M4 pipeline isn't complex enough to see the benefit of doing some work between the stores.
What we just did there is turn the 32-bit value 0x12345678 which is stored in memory as [0x78, 0x56, 0x34, 0x12] (LSB at lowest address, little endian) into [0x12, 0x34, 0x56, 0x78] by messing with it in an overcomplicated manner.
The "REV" instruction will do this, and you can get away with a single store.
LDR r1, [r2], #4
REV r1, r1
STR r1, [r0], #4
That may still be overkill. Rather than extracting bytes in little-endian order out of a 32-bit word, reversing them so we can iterate over them LSB first in big-endian order, if they're in memory in the order you want anyway just do:
uint32_t foo[] = { 0x12345678 };
bar->writeEP((uint8_t *) foo);
It really depends on the data formats on either side, but there's usually a way to do it without getting too monstrous. If this were an A-class core you could use {V}TBL and get complicated, but actually REV works just as well there, too.
Ta,
Matt
"uint32_t foo[] = { 0x12345678 };
bar->writeEP((uint8_t *) foo);"
That's it, just cast and you are done.
Thank you Matt Sealey for the reply. Today I worked on the board and found that the problem was no the cast, which, as you suggested, worked properly, but the fact that the array I am trying to output is stored into the ram.It is declared as:
__DATA(RAM3) static uint32_t multiChannel[BINS];
If I remove the __DATA attribute I'm able to read properly the content, otherwise what I get are unexpected values.I'm opening a new question about this.Thanks again,Andrea