03 Jan
Posted by: frank in: Computers, Electronics, Programming
I’ve been working with the A/D converter on the Atmel Xmega AVR processors, and it’s been quite the handful. At this point in time (Jan 2010) the parts have some very serious issues, and I’ve lost a lot of time trying to get them to work as advertised. This posting is to share what I’ve found, and the best solutions I’ve determined to get the Xmega A/D converters to work.
If you haven’t already done so, you need to read Atmel application note AVR1300, “Using the XMEGA ADC”, as well as use the source code provided with that app note.
You also need to read the errata for the Xmega. The errata is found towards the bottom of the Xmega datasheet. I should point out that the errata only gives you a hint of the problems with the part, but at least Atmel acknowledges there are some big issues. I’ve been working a lot with Atmel’s tech support, and I must say they’ve been helpful (to the extent they can be) and responsive. Supporting a broken part can’t be easy for them either. They have told me that Atmel is working on a silicon revision to fix these problems, but they haven’t been able to tell me when it might see the light of day.
OK, here we go. The code snippets below are from my code; you’ll need to edit them slightly to suit your needs. But they will show you which AVR1300 functions to use.
Singled-Ended Vs Differential
The Xmega is a differential 12-bit ADC that can be used in either singled-ended or differential mode. Initially I’d been using it in single-ended mode, just because it’s easier, and I’d been getting errors of magnitude well in excess of 30 counts (LSBs). Obviously that’s enormous. In fact the errata implies that errors of up to 60 LSBs are possible. That’s almost 6 bits! At that point it’s closer to a random number generator than an A/D converter…
The best thing to do here is use differential mode. I found the best results came from tying one of the external ADC pins to GND, and using that as the “negative” input for the converter. You want to do this with no gain. Using gain only adds more error. So your code would look something like this (change your pin names as appropriate):
ADC_Ch_InputMode_and_Gain_Config(&ADC_BK.CH0, ADC_CH_INPUTMODE_DIFF_gc, ADC_DRIVER_CH_GAIN_NONE); // differential mode, no gain ADC_Ch_InputMux_Config(&ADC_BK.CH0, pin, ADC_CH_MUXNEG_PIN1_gc); // + & - inputs
It’s possible to use the internal GND reference, but my experiments seemed to favour using an external pin tied to GND.
Xmega ADC Reference Voltage
The part has an internal 1.00V reference voltage, that you’re supposed to be able to use as the reference voltage for the A/D. In practice this doesn’t work. The errata suggests this, and suggests the 1.00V reference is too low a voltage for the ADC to function properly.
I suspect the best solution is to provide a buffered external stable reference voltage of around 2V and feed it into the part via its external reference pin. In my case this wasn’t an option so I had to settle for something else. The next best option is to use the internal setting of VCC/1.6 as the ADC reference. In such a case your code will look something like this:
ADC_Reference_Config(&ADC_BK, ADC_REFSEL_VCC_gc); // use Vcc/1.6 as ADC reference
With a 3.3V VCC, this gives a reference of 2.06V. The problem here is that the reference for an A/D is assumed to be stable. Very stable. That’s hard to claim for a VCC line, which may have all kinds of noise on it. So this falls into the “do the best you can” camp, but it’s still better than using the internal 1.00V.
If you don’t know what VCC is (perhaps you need to measure it), how do you accomplish that when VCC/1.6 is your ADC reference? The only way I know is by getting the ADC to sample the internal bandgap voltage. Something like this:
ADC_Ch_InputMode_and_Gain_Config(&ADC_BK.CH0, ADC_CH_INPUTMODE_INTERNAL_gc, ADC_DRIVER_CH_GAIN_NONE); ADC_Ch_InputMux_Config(&ADC_BK.CH0, ADC_CH_MUXINT_BANDGAP_gc, 0);
You’ll want to calibrate this yourself. The datasheet says the bandgap is 1.1V. I’ve found it’s a little less than that – more like 1.08V. There’s no way to put a multimeter on it directly, but you can get the ADC to measure it, and you can of course measure your VCC voltage, so that tells you what the bandgap actually is. Note that according to the errata, you cannot measure the bandgap if your VCC is below 2.7V, so in that case you’re probably out of luck, and you’d better look again at providing an external ADC reference voltage.
Note there is an error in the errata. (Yes, Atmel needs an errata for their errata….). Errata #4 talks about using the A/D to measure the 1.00V internal voltage reference. Atmel tech support has confirmed this is not possible – the errata is wrong. The only “reference” you can measure is the bandgap.
Signed vs Unsigned Mode
The Xmega has a 12-bit A/D. It can be run in either signed mode, or unsigned mode. If you’re measuring a simple single-ended input referenced to ground (which most folks do), the way to get the full 12-bits of resolution is to use unsigned mode. In unsigned mode, the “negative” input of the ADC is tied to an internally generated voltage which is at the approximate midpoint of the ADC reference voltage. The problem is this internally generated voltage is very unstable, which has the effect of producing widely varying ADC outputs for a stable input voltage.
The solution is to use signed mode. In signed mode, the “negative” ADC input is under your control, and should be routed to a external pin which is tied to GND (as per “Singled-Ended vs Differential” above). Signed mode is selected much like this:
ADC_ConvMode_and_Resolution_Config(&ADC_BK, ADC_ConvMode_Signed, ADC_RESOLUTION_12BIT_gc);
In signed mode, with a simple single-ended input referenced to ground, you effectively have an 11 bit converter, not a 12. Output values will typically be in the range of 0 – 2047 (0 – 0×7ff).
ADC Sampling Speed
For measuring internal signals you need to be running the ADC below 100 kHz. I’ve tried a bunch of different sampling speeds, and 62 kHz seems to be the sweet spot. If you’re using the internal 2 MHz CPU clock, this is an ADC prescaler of 32. Like so:
ADC_Prescaler_Config(&ADC_BK, ADC_PRESCALER_DIV32_gc);
ADC Offset
I’ve struggled with this one. The AVR1300 app note & example code shows a simple method of measuring the ADC’s DC offset, and subtracting it from every ADC measurement. I’ve found the DC offset to be relatively small: around -4 in my case. Yet when I try to “correct” my ADC measurements by subtracting it out, it makes my measurements less accurate, not more.
It almost makes me wonder if it’s not a real DC offset, but rather some artifact of the nonlinearity problems currently inherent to the ADC.
After much experimenting, I’ve decided not to use it. What I do is measure the ADC offset when the code starts up, and I print it out for informational purposes. But then I set the offset to zero, and leave it there. So I’m not using the offset (offset = 0 in my code) and this seems to produce better ADC results.
ADC Calibration Bytes
The AVR1300 code shows how to read the ADC calibration bytes into the appropriate ADC register. Like so:
ADC_CalibrationValues_Set(&ADC_BK);
I’ve found it doesn’t seem to make any real difference. I do indeed do it, but commenting this line out doesn’t appear to make a meaningful difference.
Averaging & Clipping
Averaging ADC measurements certainly helps reduce their sample-to-sample variability. To take an ADC measurement, I take 4 and average them. This is well worthwhile.
The other thing I do is clip them to zero. Because I’m measuring single-ended voltages, a negative voltage is not physically possible (or desired). So after my average of 4 ADC measurements, if the result is less than zero, I make the result zero. This helps in my code later, because I know I don’t need to deal with negative numbers. Otherwise, because my ADC appears to have a slight negative “offset”, measuring a grounded pin can result in an ADC measurement of -3 for example, which is not meaningful. So something like this gets clipped to zero.
Summary
To summarise a long post on the care & feeding of a currently rather broken Xmega ADC, here are my hard-earned suggestions:
Good luck! Let’s hope Atmel releases fixed silicon really soon.
Atmel kindly gave me an Xplain Xmega board at one of their Xmega seminars. It’s a useful tool for ATXmega development, but it does have a couple of problems. I thought I’d mention the ones I’ve tripped over, in case anybody else sees the same problems.
Board Doesn’t Restart Properly
I’ve found that when the AVRISP2 programmer is plugged in, the Xplain always reboots properly. But when the programmer is unplugged and the board is “on its own”, so to speak, it doesn’t always reboot properly and the code in the Xmega128 doesn’t always run.
The reason is a hardware problem on the board. Atmel’s Xmega documentation states that the Xmega processors have a weak internal pullup on the reset line. If there are any external devices on the reset line, an additional external pullup may be required.
This is the case with Xplain. The ATXmega128 reset line also routes to the AT90USB1287 part on the board. It seems this small additional load is problematic for the Xmega. Adding a 10k pullup resistor to the Xmega reset line solved the problem and allowed the Xmega to reboot properly every time.
Take a look at the Xplain schematic (available on the Atmel website) to see where the reset signal goes. Personally, I found it very easy to solder an 0603 10k resistor on the back of the Xmega programming connector header, between pins 4 & 6. The 0603 was the perfect size to fit between the solder joints for pins 4 & 6 on the back of the board. But, a regular leaded resistor would work fine too.
USB Serial Interface Doesn’t Work
Yep, lots of people have pointed that out. The AT90USB1287 is supposed to implement a “virtual COM port”, allowing the Xmega to transmit & receive at 9600 board, and have that available over USB thanks to the 1287. In theory. In practice, not so much. Atmel’s USB-to-serial interface doesn’t seem to work as advertised. I was able to confirm on my board that I was giving the AT90USB1287 the 9600 baud serial data it expected, but the thing never worked. I tried different drivers etc from the Atmel website, to no avail.
In theory you can reprogram the 1287 via the USB port, using Atmel’s “FLIP” utility (available on their website). For me, that didn’t work either, and I really tried hard. No FLIP for me!
So what to do? Here are a couple of options.
Programming Atmel AVR processors has become a little more difficult with Atmel’s use of a 6-pin connector on their popular AVRISP2 programmer. This is a great little programmer, fast, cheap, and USB based.
But why oh why did they put a 6-pin connector on it, instead of the 10-pin connector they use almost everywhere else? Almost all of their development boards, including the Xplain, have 10-pin programming headers. But this little programmer has a 6-pin connector. So you need to make yourself an adaptor board, or adaptor cable, before you can even use it. What were they thinking?
In fact, ideally you need to make two different 6-to-10 pin adaptors. One for Xmega devices that use the PDI programming interface (see my previous post), and a different one for all the other AVR parts that use the older “SPI” or “ISP” programming interface.
There you have it. A pull-up resistor to cure the “Xplain doesn’t reset” problem, and a couple of options if your Xplain USB to serial doesn’t work. Have fun!
This is a surprisingly common question. When using WinAVR, how do you get printf() working on an Atmel Xmega processor? Hopefully this post will help explain how.
First of all, this documentation page has some good information regarding the different flavours of WinAVR printf:
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html
Note the existence of the printf_P() function, which makes it easy to work with strings kept in program space (flash). This can be super useful on an AVR, which has very little SRAM but loads of flash. The regular printf() function will put your text string in SRAM, which is not always ideal.
The big question after reading that documentation page is: how do I initialise the UART, and how do I implement the putchar function, on an Xmega? Because the example code on that webpage is geared towards the non-xmega parts.
Here’s some Xmega example code. Feel free to use it however you see fit.
#include <stdio.h> #include <avr/io.h> static int uart_putchar(char c, FILE *stream); static void uart_init (void); static FILE mystdout = FDEV_SETUP_STREAM (uart_putchar, NULL, _FDEV_SETUP_WRITE); int main (void) { uart_init(); stdout = &mystdout; while (1) printf("Hello, world!\n"); } static int uart_putchar (char c, FILE *stream) { if (c == '\n') uart_putchar('\r', stream); // Wait for the transmit buffer to be empty while ( !( USARTC0.STATUS & USART_DREIF_bm) ); // Put our character into the transmit buffer USARTC0.DATA = c; return 0; } // Init USART. Transmit only (we're not receiving anything) // We use USARTC0, transmit pin on PC3. // Want 9600 baud. Have a 2 MHz clock. BSCALE = 0 // BSEL = ( 2000000 / (2^0 * 16*9600)) -1 = 12 // Fbaud = 2000000 / (2^0 * 16 * (12+1)) = 9615 bits/sec static void uart_init (void) { // Set the TxD pin high - set PORTC DIR register bit 3 to 1 PORTC.OUTSET = PIN3_bm; // Set the TxD pin as an output - set PORTC OUT register bit 3 to 1 PORTC.DIRSET = PIN3_bm; // Set baud rate & frame format USARTC0.BAUDCTRLB = 0; // BSCALE = 0 as well USARTC0.BAUDCTRLA = 12; // Set mode of operation USARTC0.CTRLA = 0; // no interrupts please USARTC0.CTRLC = 0x03; // async, no parity, 8 bit data, 1 stop bit // Enable transmitter only USARTC0.CTRLB = USART_TXEN_bm; }
This code shows the things you need to do, in its most basic form. It only demonstrates transmitting out the UART; there’s no receive here (we are talking about printf, after all). This code:
Note the initialisation sequence. With the Xmega it’s important to manually set the UART transmit pin, ie the corresponding port pin, as an output, and set it high, before configuring the UART. This is specified in the Xmega documentation, and is different to most other AVR parts which don’t have this requirement.
Note also that the UART is set to 9600 baud, no parity, 8 data bits, 1 stop bit. I have this code running on an ATXmega128 board (an Atmel Xplain board).
This should be enough to get things started, and you can build on it from here.
A little while ago I wrote about implementing fast JPEG encoding on an Analog Devices Blackfin. See the original post here:
Since then I’ve moved to a new hardware platform, with a different blackfin processor and a different image sensor, which has caused me to revisit this code. I found that with the previous code, image quality wasn’t as good as I thought it should be. Sometimes the jpeg image looked a little blocky, or pixelated. Not a lot, but a little bit, enough to notice.
Some digging revealed that it seemed to be related to the DCT (discrete cosine transform) function. In the Surveyor code there are two DCT functions. One, called DCT, is written in C. The other, called r8×8dct, is written in assembler by Analog Devices. By default the jpeg encoder uses the assembler version, and rightfully so, because it’s a lot faster. But I found that when I switched to using the C “DCT” function, image quality was improved, and the jpg images looked like I’d expect them to.
As a result, I wrote an assembler implementation of the C “DCT” function, which is functionally identical to the C code, but a great deal faster. For my 752 x 512 YUV image, these are the speeds I measured for jpeg encoding:
You can see that my DCT assembler function is not quite as fast as the Analog Devices one. But it’s very close; only 2 ms difference. Close enough! The new assembler DCT function is called jpegdct. I’ve revised the .zip file to remove the Analog Devices assembler function, and use my new one. This also has the side benefit that all of the source files are now under the GPL license. The new files are here:
Blackfin Fast JPEG Encoder Files
So there we have it. A fast JPEG encoder, fully GPL, and improved image quality. What more could we wish for?
Recently I’ve been doing some Atmel AVR Xmega work. The Atmel website says that their low-cost programmer, the AVRISP2, can be used to program an xmega device. But their (current) documentation would appear to tell a very different story. If you read the documentation, you’d reasonably conclude that it wouldn’t work at all.
In fact the AVRISP MkII can be used to program an Xmega part. You just need to know how to hook it up.
First of all, make sure you’re using the very latest version of AVR Studio, as you’ll need to use that as your programming software. (AVR Studio also contains a decent IDE, and a plugin to support the free WinAVR C compiler, so it’s actually much more than just a programming program, if you want it to be.)
The AVRISP2 has a 6-pin header. Here’s how to connect it to an Xmega part:
AVRISP2
PIN1 - xmega PDI data pin
2 - xmega VCC power rail
3 - no connect
4 - no connect
5 - xmega PDI clock (often the xmega reset pin)
6 - xmega GND power rail
That’s it. Only 4 pins to hook up. Now you can tell AVR studio which xmega part you have, select the AVRISP MkII programmer, and program away. Easy!
Those in the know, know, that if you want to play with analog circuits, using a simulator first is a really good idea. There are many analog circuit simulators out there, some free, some mega-bucks, but the most common of all is SPICE. There are many different versions of SPICE available, and lately I’ve been using one that I’ve really been enjoying, called LTspice. You can download it here:
http://www.linear.com/designtools/software/
LTspice is a free program provided by Linear Technology. Some of you may know it by its older name, SwitcherCAD, but it’s actually a full SPICE simulator. LinearTech provides models for almost all of their parts with LTspice, in addition to a large number of models for other popular parts, like various transistors, diodes, etc. What’s nice is that if LTspice doesn’t contain a model for your MOSFET of interest for example, but you can find a spice model on the MOSFET manufacturer’s website, just copy&paste that model into LTspice and you’re good to go.
It also comes with lots of example circuits, and there’s a users manual on the website. For a free program it’s pretty well developed.
Here’s a simple example. Today I had an R-C circuit controlling a reset controller, and I wanted to know how long the R-C would take to reach a certain voltage to trip the controller. Well, it would be easy enough to work that out with a little math, but it’s way more fun to simulate it.
Click (twice) on the picture above to enlarge it. You can see the little schematic I drew, and the resulting classical R-C charging curve in red in the graph above. Quick, simple & easy. What’s nice is that I can now easily extend this circuit, adding for example a current sink on the Vout line to simulate the load of my controller, and see the result on the R-C curve. This kind of tool makes experimentation and “what-if” thought processes very easy & informative.
If you’ve never used a SPICE simulator before, or you’re just interested in learning more about how some of these simple circuits (or much more complex circuits) actually work, I’d encourage you to download LTspice & give it a try. It’s a really great tool.
Here’s a little known fact about SD Cards. The little “lock” switch on the side of the card? It doesn’t lock the card.
This is a photo of a pretty typical SD card. On the left you can see the “lock” switch. You’d think that sliding this switch downwards, into the locked position, would write-protect the card. You’d be wrong.
I first stumbled across this fact on vacation, where at an internet cafe I ended up with a virus on a “locked” SD card.
The lock switch does nothing to the internals of the card. There is no switch or any electrical mechanism in the card. That switch is nothing more than a movable piece of plastic. The card itself has no idea whether the switch is in the locked, or unlocked, position.
In your card reader is a mechanism which senses the position of that lock switch, and reports its position back to the PC. The PC, ie the operating system or file manager in the PC, then has the option, if it so chooses, of not writing to the card if it knows the lock switch is in the locked position. However, it can just as easily ignore it. Electrically, there is nothing preventing it from writing to the card. This is what a virus can easily do. If there is a problem with your OS or file manager program and it ignores the switch position, it too will happily write to a “locked” SD card.
So beware. Don’t assume your card is safe simply because the switch says it’s locked. The card can still be written to, re-formatted, the card contents erased, etc. Accidents most certainly can happen, even though the switch is “locked”. It’s not locked, it’s never truly locked, so treat your card, and its contents, with all appropriate due care & respect. I’ve no idea why the people who designed the SD card implemented a lock switch that doesn’t lock, but they did, and we’d be wise to remember that little fact.
One of the most frustrating and annoying programs on my Windows computers used to be the Adobe PDF reader. Back in its early versions it was a fast, light, useful program. Then a few years ago somebody at Adobe drank a bottle of liquid stupid, and the program’s been hurtling downhill ever since.
The problems with the reader are plentiful, but some big ones come to mind. That whole period where the reader basically forced you to install the Yahoo toolbar was a disaster. The current Adobe Updater (forced upon you with Adobe Reader) is even worse. I can’t count the number of times that either the reader, or its updater, has either flat-out crashed one of my machines, or bought it to its knees. I’ve tried every version, right up to the very latest, and the only thing I can say with confidence is: Don’t Upgrade. Whatever problems you might be having with the Adobe PDF reader today, installing a newer & even more bloated version will only make things worse.
That’s the bad news. The good news is, there are some really fantastic alternatives. I don’t use the Adobe PDF reader, or writer, anymore, and you don’t need to either. And even better news: these greatly superior programs are free!
There are a few different alternatives to the Adobe software. You can research & compare them all, as I did, but in this post I’m going to cut to the chase and simply tell you what I use & recommend.
Use the PDF-XChange PDF Viewer. You can download it for free here:
http://www.docu-track.com/downloads/users/
This has all the features of the free Adobe reader, plus a lot more. This one will also allow you to edit PDFs, something that you’d otherwise need to use the paid $$ version of the Adobe reader to do.
Once you have this program installed and you’ve confirmed it works, feel free to go to your Start – Settings – Control Panel – Add or Remove Programs and remove the Adobe PDF reader. You won’t be needing it anymore.
Want to create your own PDFs for free? Yep, I thought so. It’s very easy to do. Download and install PDF Creator from here:
This program installs itself as a printer driver on your computer. Now you can generate a PDF from any program at all; word processing, spreadsheet, photo, etc. All you need to do is go File – Print within your program of choice, and select the “PDF Creator” printer instead of your normal printer from the drop-down box. After you hit “print” it’ll ask you for a file name for your newly-created PDF file. Life doesn’t get any easier than that.
That’s it! A couple of free, fast, well-functioning programs for reading, editing & creating PDF documents. Install these two, uninstall the Adobe programs, and you’ll have a smoother-running, more functional, PC.
Reading through the websitebaker themes website, I came across this rather remarkable, and amusing, sentence, and felt compelled to post it here:
Aoccdrnig to rscheearch at an Elingsh uinervtisy, it deosn’t mttaer in waht oredr the ltteers in a wrod are, the olny iprmoetnt tihng is taht the frist and lsat ltteer is in the rghit pclae.
Hilarious.
Recently I’ve been doing a lot of embedded uClinux programming for the Analog Devices Blackfin BF537 processor. Writing drivers, application code, things like that. It’s a lot of fun.
![]()
One of the things I’d been battling with was finding a reasonably fast JPEG encoder. Now you need to understand that the BF537 doesn’t have a JPG compression engine or anything like that, so it’ll never be screaming fast. The default uClinux JPEG library is libjpeg. Libjpeg is fairly slow. I wrote a reasonably-optimised DCT function in blackfin assembler for libjpeg & posted it over at http://blackfin.uclinux.org You can find the files, and a description, here at my original posting:
Faster JPEG encoding – files attached
What’s cool is it appears to have been accepted into the mainstream blackfin uClinux distribution (SVN), judging by this tracker entry. So pretty soon everyone will be getting this faster libjpeg code by default.
Which is nice, and it helps, but it’s still too slow. My example 752 x 512 RGB image was taking around 260 ms to JPG encode using the “improved” libjpeg function. Too long. So I looked for alternatives.
I had tried FFMPEG. It’s faster, because the Analog Devices folks wrote some optimisations for it. It’s tricky to tell exactly how fast, because FFMPEG will duplicate frames to give you the framerate you request. Just because FFMPEG gives you 25 frames/sec doesn’t mean you’re getting 25 different frames per second. But that aside, the big problem I had with FFMPEG was its tendancy to malloc() and free() chunks of memory constantly. This would eventually result in memory fragmentation & malloc() failing, sometimes in minutes, sometimes in hours. Problems like this I can do without, and it’d be a hard one to fix.
SCS Vision wrote a JPEG encoder for their leanXcam product. Their encoder appears to be based on one written by Nitin Gupta. Based on comments they wrote in their comment block (which I assumed to be correct & did not personally verify), I calculated it would encode my image in around 290 ms. Obviously that’s not the big improvement I’m looking for.
Analog Devices has a very fast optimised JPEG encoder available, right off their Blackfin website, for free. But it only works with their proprietary VDSP+ tools. It’s not compatible with any of the open-source tools (gcc, uClinux, etc) and it’s only distributed in object code form, which makes it impossible to port. Tantalising, but useless.
Then recently I had a break. I stumbled across the Surveyor robot folks. A very bright fellow over there wrote a pretty decent JPG encoder, which took advantage of an Analog Devices optimised DCT function, as well as doing some other smart things in the code. It only handled YUV images, whereas my image is RGB. So before I could try it, I had to hack up a quick RGB24 to YUV422 conversion routine. But once I did, I was encoding my image in 165 ms. That’s clearly a substantial improvement over the libjpeg 260 ms.
With that success, I set to further optimising the code, both theirs and mine. By the time I was finished, my image was JPEG encoding in 96 ms. Go baby go!
Fast JPG encoding seems to be a common question for Blackfin, so I’m posting the final code here. Click on the link below to get to the download page:
Now here’s how to call the function.
If you’re familiar with libjpeg, you’ll find this easier, because there’s nothing to set up or tear down. encode_image() needs a pointer to the raw image in memory, a pointer to a chunk of memory where it can write the resulting JPG image, and a few other parameters. It returns another pointer, which is the next free location in memory where it had just been writing. So that you can work out how large the just-created JPG image is. It’s up to you to write the JPG image to a file (if indeed you even want to do that).
Here’s the function prototype:
UINT8* encode_image (UINT8 *input_ptr, UINT8 *output_ptr, UINT32 quality_factor, UINT32 image_format, UINT32 image_width, UINT32 image_height);
It’s pretty simple. Pointers to the input raw image buffer (YUV or RGB) and an output image (JPG) buffer. A quality factor which ranges from 1 (highest) to 8 (lowest). I use 2. Setting this to 1 results in much longer execution time & much larger filesizes. Image format can be:
FOUR_ZERO_ZERO (monochrome YUV) is reported in the comments below as also working.
Image width & height should be self-explanatory.
To call it, set up your image buffers as you see fit, then do something like this:
jpeg_buff_end = encode_image(text_img_buff, jpeg_buff, 2, RGB, 640, 480);
Your JPG image is of filesize: (jpeg_buff_end – jpeg_buff)
If you want to save your JPG to a file, you can do something like:
jpegfp = fopen ("myimage.jpg", "w"); fwrite (jpeg_buff, 1, jpeg_buff_end-jpeg_buff, jpegfp); fclose (jpegfp);
That’s it. Easy to use, and it’s the fastest thing, by far, I’m aware of for JPEG encoding on Blackfin uClinux.
| M | T | W | T | F | S | S |
|---|---|---|---|---|---|---|
| « Jan | ||||||
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 |
| 15 | 16 | 17 | 18 | 19 | 20 | 21 |
| 22 | 23 | 24 | 25 | 26 | 27 | 28 |
| 29 | 30 | 31 | ||||