Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 12:18 03 Aug 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : V4.7 : MX170 SDCard FAT32 Driver

     Page 2 of 3    
Author Message
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 03:22pm 11 Aug 2015
Copy link to clipboard 
Print this post

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.

  Quote  SPIOpen = true;
SPIOpen = false;

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 Kingdom
Posts: 10315
Posted: 01:02am 12 Aug 2015
Copy link to clipboard 
Print this post

  Quote  Ah, co-existence !!


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 Zealand
Posts: 2442
Posted: 03:50am 12 Aug 2015
Copy link to clipboard 
Print this post

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 Zealand
Posts: 9610
Posted: 04:17am 12 Aug 2015
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 676
Posted: 03:33pm 12 Aug 2015
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 10315
Posted: 09:05pm 12 Aug 2015
Copy link to clipboard 
Print this post

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: Australia
Posts: 1329
Posted: 04:23am 13 Aug 2015
Copy link to clipboard 
Print this post

@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've got your second version of the SD card program running fine (beta 23) on Mick's SMD BackPack 170 using the SD card on a 2.4" screen module and with a reasonably old 8GB card. I started off using Jim's MMEdit (as pretty much always) but couldn't see the actual logged data either on MMEdit as it ran, or on the laptop (Win XP) when I checked the output with Excel(2003). I could see all the pre-amble info and logging headers but not the data.

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 Kingdom
Posts: 676
Posted: 07:54am 13 Aug 2015
Copy link to clipboard 
Print this post

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

PeterEdited by G8JCF 2015-08-14
The only Konstant is Change
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 08:15am 13 Aug 2015
Copy link to clipboard 
Print this post

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

PeterEdited by G8JCF 2015-08-14
The only Konstant is Change
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 09:04am 13 Aug 2015
Copy link to clipboard 
Print this post

1st try - 44-pin - perfect
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 10:36am 13 Aug 2015
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 10315
Posted: 09:35pm 13 Aug 2015
Copy link to clipboard 
Print this post

  Quote  Hopefully it now does what you need


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.




Edited by matherp 2015-08-15
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1329
Posted: 04:25am 14 Aug 2015
Copy link to clipboard 
Print this post

  G8JCF said   Hi Greg
The problems you are seeing are, I think, due to NULLS.
....
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. Peter


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.Edited by paceman 2015-08-15
 
G8JCF

Guru

Joined: 15/05/2014
Location: United Kingdom
Posts: 676
Posted: 04:38am 14 Aug 2015
Copy link to clipboard 
Print this post

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


Edited by G8JCF 2015-08-15
The only Konstant is Change
 
paceman
Guru

Joined: 07/10/2011
Location: Australia
Posts: 1329
Posted: 11:01pm 14 Aug 2015
Copy link to clipboard 
Print this post

  G8JCF said  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

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: Australia
Posts: 6283
Posted: 11:47pm 14 Aug 2015
Copy link to clipboard 
Print this post

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: Australia
Posts: 1329
Posted: 02:21am 15 Aug 2015
Copy link to clipboard 
Print this post

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

Edited by paceman 2015-08-16
 
Frank N. Furter
Guru

Joined: 28/05/2012
Location: Germany
Posts: 949
Posted: 12:44am 01 Dec 2015
Copy link to clipboard 
Print this post

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 Kingdom
Posts: 4044
Posted: 01:13am 01 Dec 2015
Copy link to clipboard 
Print this post

Where's the source code?

With that, someone can make changes / rebuild it.

John
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10315
Posted: 01:40am 01 Dec 2015
Copy link to clipboard 
Print this post

  Quote  Where's the source code?


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.
 
     Page 2 of 3    
Print this page
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025