![]() |
Forum Index : Microcontroller and PC projects : V4.7 : MX170 SDCard FAT32 Driver
![]() ![]() ![]() ![]() |
|||||
Author | Message | ||||
G8JCF![]() Guru ![]() Joined: 15/05/2014 Location: United KingdomPosts: 676 |
PeterM Ah, co-existence !! I'll certainly take a look at what you've said although it does seems somewhat brutal to have to do an spi open/close on every call rather than using CS to select the target. I think that MMBasic might need to have a "handle" count for the SPI channel(s) - in fact for any port/device which can be shared amongst multiple drivers so that for example releasing a port only happens when the handle count is 0, and when the handle count is non-zero all parties know other parties are sharing the common device/port - this is all beginning to feel very familiar from my days of the early 1980 when I wrote an RTOS in 6809 and had to have a Device Control Block structure for each shared device, to keep track of who/what was doing stuff with a given I/O channel at any instant in time. As for implementing stuff in the MMBasic wrappers, I don't like doing that because it creates a "messy" set of code which is more subject to corruption. I only implemented the MMBasic function wrappers for improved userability [sic]. What I will try to do is find a way for the SPI code in the FAT32 driver to save and restore the state of the SPI port on every call it makes at the high level, ie just after MMBasic calls into the CFunction, but before the lower level calls are made into the sector/cluster write functions. If needs be, I'll add a driver function call to permit the the MMBasic program to specify the speed to put the SPI port back to after each use by the driver (so that the FAT32 driver can operate at 10MBits/s for optimal performance), and other devices will run at whatever speed. BTW, I don't recall seeing a SPIOpen MMBasic API call/variable - I do have one of course inside my FAT32 driver CFunction so that it can keep track of what's going on internally to itself, but I don't know of a global flag which is visible to both the MMBasic interpreter and CFunctions, I must have missed that one or misunderstood what you mean above. Re: loading 512 byte blocks from the SDCard, yes I'll implement that, that's very straightforward. The form of the call will be Function File.Read.BlockI(Array%,NumBytesToRead%,BytesActuallyRead%) as Integer Function File.Read.BlockS(Array!,NumBytesToRead%,BytesActuallyRead%) as Integer Unfortunately there is no easy way for a CFunction to determine how many elements there are in an array AFAIK, and MMBasic doesn't permit overloading so we have to have different function names You could of course call the existing File.Read function 4 times in succession with a Buffer$ of 128 bytes and each time transfer the 128 bytes into another array, eg 'Declare a 512 byte block, ie 4 * 128 Dim SectorBuffer%(127) 'Declare a 128 byte block for file Read operations Dim Buffer$=String$(128,chr$(0)) 'Loop variable Dim I%=0 'Which block of 128 bytes we're processing currently Dim Block%=0 'Go get 128 bytes File.Read(Buffer$,NumBytesRead%) 'Copy 128 bytes from string into memory For I%=(Block% * 128) to (Block% * 128) + 127 Poke Byte SectorBuffer%, I%, ASC(Mid$(Buffer$,I%+1,1)) Next I% 'Make this into a separate MMBasic Function Block%=Block%+1 'Go get 128 bytes File.Read(Buffer$,NumBytesRead%) For I%=(Block% * 128) to (Block% * 128) + 127 Poke Byte SectorBuffer%, I%, ASC(Mid$(Buffer$,I%+1,1)) Next I% Block%=Block%+1 'Go get 128 bytes File.Read(Buffer$,NumBytesRead%) For I%=(Block% * 128) to (Block% * 128) + 127 Poke Byte SectorBuffer%, I%, ASC(Mid$(Buffer$,I%+1,1)) Next I% Block%=Block%+1 'Go get 128 bytes File.Read(Buffer$,NumBytesRead%) For I%=(Block% * 128) to (Block% * 128) + 127 Poke Byte SectorBuffer%, I%, ASC(Mid$(Buffer$,I%+1,1)) Next I% 'Should now have 512 bytes in SectorBuffer% 'Untested, but U never know it might work :) So much to think about ! Peter The only Konstant is Change |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10315 |
Peter I have a suggestion for a neat way round this. The MX170 support two SPI channels but Geoff has only made one available. You could use the other one. A possible pinout on the 28-pin chip, trying to miss other advanced function pins, is as follows: SPI2_CLK : fixed on pin 23, PortB12, no advanced functions SPI2_OUT : PPS allocate pin 24, PortB13; compromises PWM2B SPI2_IN : PPS allocate pin 6, PortB2, compromises PWM1C The net effect is that when you are using the SDCard you lose 2 PWM channels but can still have 2 on PWM1 and one on PWM2 This then completely decouples SD card SPI usage from any other usage. |
||||
robert.rozee Guru ![]() Joined: 31/12/2012 Location: New ZealandPosts: 2442 |
correct me if i am wrong, but is the problem with mixing 'internally supported' SPI peripherals (TFT LCD and touch screen) with the 'external' use of the same SPI channel by mmbasic's SPI commands? IF this were the case, would one solution be for geoff to move the LCD and touch screen functionality over to the 2nd SPI channel, while keeping the 1st SPI channel reserved for BASIC program access only? now given that custom functions are so closely integrated with the interpreter, it would THEN be possible to (perhaps) have your SD card support also use that 2nd SPI channel - internally, the interpreter could have hooks added to co-ordinate sharing the 2nd SPI channel between TFT LCD, touch screen, and your SD card custom function. so, a micromite II equipped with TFT LCD, touch screen and SD card would have all 3 of these peripherals operating on the 2nd SPI channel. but that SPI channel would not be accessible from BASIC. support for TFT LCD and touch screen would still be 100% internal to the mmbasic interpreter, while SD card access would be 99% implemented as a custom function. cheers, rob :-) |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9610 |
On the E64 MM+ module, Geoff's firmware does exactly that. The SD card, SPI LCD and touch commands all work on the 2nd SPI port, leaving SPI1 for MMBASIC to use for normal SPI tasks. Smoke makes things work. When the smoke gets out, it stops! |
||||
G8JCF![]() Guru ![]() Joined: 15/05/2014 Location: United KingdomPosts: 676 |
Hi - thank you for the tip. I now have two versions of the CFunction Fat32 driver both the same size, the difference is just one compile time #define which determines which code blocks get compiled dependent on which SPI port is going to be used. 1) Uses SPI1 2) Uses SPI2 I did try and have a single driver binary, and at runtime enable the caller to specify which SPI port to use, but it added about 1.5KBytes of extra code to the binary, so I decided against that strategy - however I will re-visit it again, and see if I can crunch down the overhead because it would be much neater to have just a single driver binary, although I guess that because of the potential for a clash with the SPI TFT LCD's the SPI2 version might be more popular. 'PIC32MX170 28 Pin wiring 'Pin 2 Chip Select can be any digital output pin ' SPI 1 SPI2 'MOSI Pin 3 Pin 24 'MISO Pin 14 Pin 9 'SCLK Pin 25 PIN 26 ' 'PIC32MX170 44 Pin wiring (untested) 'Pin X Chip Select can be any digital output pin ' SPI 1 SPI2 'MOSI Pin 20 Pin 11 'MISO Pin 41 Pin 30 'SCLK Pin 14 PIN 15 Do people have a preference on which pins SPI2 should be mapped to ? I will publish the new driver pair tomorrow. G'Nite Peter The only Konstant is Change |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10315 |
Peter Personally, for the 28-pin, I would choose: ' SPI 1 SPI2 'MOSI Pin 3 Pin 6 (PortB2) 'MISO Pin 14 Pin 24 (PortB13) 'SCLK Pin 25 PIN 26 (PortB15) The general feel I get from reading peoples' comments on other threads is that serial ports are more important than losing another PWM channel. Sorry about getting the clock pin wrong on my previous post, I had a bad day yesterday reading datasheets and confused 28-pin QFN with 28-pin DIP, I think I've got it correct this time ![]() |
||||
paceman Guru ![]() Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
@G8JCF Hi Peter, As the others have all said - this is a great effort. Here's a bit of a trap for young players though (old ones too ![]() I was using MMEdit's "capture" feature to get the output and somehow that seems to affect it. It turns out the data is there but it's way over to the right of the screen using "capture" - it doesn't do it with TeraTerm. The issue is that I normally restrict the window I use for MMEdit a bit, i.e. to the end of it's menu bar, but the run-time logged data I see coming back to the MMEdit screen ends up to the right of that, consequently unseen. The same's true with Excel set at full screen, the data's there but way to the right - so it must be written to the card. It had me for a while but there seems to be something unprintable hidden there. BTW when I first tried to get it going it came back with a 'Failed disk init', the next time (after card re-insert) it gave a 'Failed driver init', the next time (after power cycle) another 'Failed driver init', then finally all ran properly after closing MMEdit "Chat", and pulling then re-installing the USB cable. It's runs quite reliably now. Greg |
||||
G8JCF![]() Guru ![]() Joined: 15/05/2014 Location: United KingdomPosts: 676 |
Thank you PeterM for the advice about pin usage which I have incorporated. Here is the Fat32 SDCard Driver operating using SPI2. The Pin numbering is 'PIC32MX170 28 Pin wiring 'Pin 2 Chip Select can be any digital output pin ' SPI 1 SPI2 'MOSI Pin 3 Pin 24 'MISO Pin 14 Pin 6 'SCLK Pin 25 PIN 26 ' 'PIC32MX170 44 Pin wiring 'Pin 2 Chip Select can be any digital output pin ' SPI 1 SPI2 'MOSI Pin 20 Pin 11 'MISO Pin 41 Pin 23 'SCLK Pin 14 PIN 15 Changes:- 1) As suggested by PeterM, I have added a new function call File.Read.Block which returns NumBytes of bytes into the callers Integer Array. 2) Also, again as suggested by PeterM, I have added a new function call, File.Driver.Open which does File.Driver.Init, File.Disk.Init and File.Mount as one single call (the original calls have been left in) 3) Also the File.Open call can take a parameter Mode% which specifies if data is to be automatically flushed to disk on every File.Write - safest, but slower. 4) The SPI clock now runs at CPU Speed / 4 rather than being fixed at 10 MBits/s 2015-08-13_174934_SDCardDriverExample_SPI2_V1.7_Prod.zip and a blank logfile.csv 2015-08-13_175001_logfile.zip Hopefully this works better ![]() Peter The only Konstant is Change |
||||
G8JCF![]() Guru ![]() Joined: 15/05/2014 Location: United KingdomPosts: 676 |
Hi Greg The problems you are seeing are, I think, due to NULLS. The blank logfile.csv is filled with NULL characters, ie &h00, 10,485,760 of them ! Tera Term, I assume, just discards/ignores NULL characters, whereas perhaps MMEdit's chat screen doesn't discard NULLs - I've switched to using Tera Term rather than MMEdit's chat window. In the latest Example code in the previous post, I have added code to not send NULLs to the serial port when displaying the log records so that might look better in the MMEdit chat window. I also assume that Excel (XP) doesn't throw away NULLs hence the problem you see. I have Excel(2007) and it doesn't exhibit the problem you describe. And, despite what I said about Libre Calc being able to handle .CSVs, I just tried to load logfile.csv into Libre Calc, and Libre Calc seems to be hanging - those millions of NULLs must be causing it a problem. I wonder if it would be better to have an empty file filled with SPACE, ie 0x20, characters instead ? edit : you can use cat logfile.csv | tr -d '\000' > logfile_clean.csv to strip NULLs from the logfile under LINUX, but I can't for the life of me find a similar simple trick for Windows Take care Peter The only Konstant is Change |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10315 |
1st try - 44-pin - perfect ![]() |
||||
G8JCF![]() Guru ![]() Joined: 15/05/2014 Location: United KingdomPosts: 676 |
Thank you PeterM ! Hopefully it now does what you need (for your LoadBMP to TFT CFunction ??? ![]() PeterC The only Konstant is Change |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10315 |
Peter Just looked at the code properly and I'm afraid the answer is no ![]() I want the File.Read.Block to be a true CFunction call which just loads the sector into the array. You already know this, but CFunctions don't know or care what the datatype of the calling program is. So I can call the CFunction with: i%=File.Read.Block(buff%()) but in the Cfunction you can treat it as: char *C I've done this before and it works perfectly (in this ) In this way you should be able to just use my array as the destination for the disk sector read. Your Basic version would work but will be far too slow for moving image files. A 320x240 picture is 153,600 bytes. Also in your code the integer array is 128 long, whereas it should only need to be 64 (64 words * 64 bits / 8 bits per byte =512 bytes) Sorry... ![]() UPDATE I've got the display code working using 128-byte reads (see separate thread) but I'm sure we can up performance further based on the proposed mechanism above. |
||||
paceman Guru ![]() Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
Thanks for the explanation Peter - I'll give the new version a go and see if that works with MMEDit. I'll have to set up another barebones 170 first though because the new SPI2 version (above) with the changes has a pin clash with Mick's board that I'm currently using (pin 26, brightness control). BTW does the new logfile you posted contain nulls still or spaces? Greg Edit: I'm afraid I haven't a clue about Linux (mores the pity) so can't try that possibility. |
||||
G8JCF![]() Guru ![]() Joined: 15/05/2014 Location: United KingdomPosts: 676 |
Hi PeterM I was going to add read block as a CFunction, but I just put in the MMBasic version as a starter whilst I was posting the code yesterday. edit : the hazards of spending too much time in C - I just got so used to integers being 4 bytes rather than 8 as in MMBasic ![]() edit : I'll code up a CFunction file.read.block function, but the caller will have to specify the number of bytes to read because unlike with a string where the first byte contains the length in bytes of the string, there is no way, afaik, for a CFunction to determine the number of elements/bytes in the variable being pointed to. Hi Greg I've got a BP170, so I'll give it a try with that, but as you say pin 26 is connected to a transistor for brightness control so it may not work. BTW, If you look at the MMBasic code you should see the statements which attempt to avoid printing NULLs to the console, and you should be able to use that same code in the SPI1 version. Take care Peter The only Konstant is Change |
||||
paceman Guru ![]() Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
Hi Peter, I un-soldered the diode (brightness control connection) to pin 26 on Mick's board so that I could try your new SPI2 version. Your changes have brought the logged data up so it can be seen properly now although there's a dump ("Dump 1st log record sector") appended to the end of the logged data. Not sure if you intended that or not. Interestingly the output is still different between using TeraTerm and MMEdit/Chat/Capture - you can see it in the first logged record. I'll upload those two output files and the output logfile and an .xls file saved after looking at it with Excel - which looked totally normal. 2015-08-15_090005_G8JCF_SD_Card.zip Cheers, Greg |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6283 |
One difference I can see between the Teraterm and MMEdit files is TeraTerm seems to ignore nulls while MMEdit doesn't. This is where the HEX view in MMEdit comes in handy. Jim VK7JH MMedit |
||||
paceman Guru ![]() Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
Hi Jim, Yes, Peter thought NULLS were the issue (see his post above 4:15 a.m.) and it looks like they are. As you say, it's good you can see this if you need to, using the hex view of MMEdit but it also means you can run into the issue I did using the normal view which leaves you scratching your head - and you have to know to look. Maybe it'd be worth having an option in MMEdit to ignore or not ignore nulls? Using TeraTerm routinely to look at run-time output is easy enough and probably more robust I guess, but the Chat window is much handier. Greg |
||||
Frank N. Furter Guru ![]() Joined: 28/05/2012 Location: GermanyPosts: 949 |
Hi to all, is there a way to adapt this brilliant SDCard FAT32 Driver to Micromite V5.0? Did anybody know what's about with Peter Carnegie? His website (http://www.g8jcf.dyndns.org) with his very usefull helps for CFunctions is down... ![]() I need his driver to load pictures from SD-Cards with Matherps great "Pictures from SD card" program... Frank |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 4044 |
Where's the source code? With that, someone can make changes / rebuild it. John |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10315 |
Unfortunately Peter Carnegie never released the source code and has since stopped working on Micromite. As a background task I am slowly working to re-create something similar. So far I have got the SDcard to initialise and to mount but there is a long way to go. |
||||
![]() ![]() ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |