SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Modérateurs : Papy.G, fneck, Carl
- Carl
- Modérateur
- Messages : 13253
- Inscription : 08 avr. 2007 13:21
- Localisation : http://www.doledujura.fr
- Contact :
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Je viens de faire un autre wav de donkey Kong avec 2 niveaux d'amplifications et le programme se charge mais finalement le jeu plante... donc ce n'est pas un soucis de LEP uniquement... ça va pas être simple... je ferai d'autres tests de lecture wav depuis mon pc portable avec le volume au 3/4....
CARL
CARL
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
C'est à cause de ces problèmes sans fin que j'ai définitivement abandonné les cassettes pour mes ordinateurs de collection.
C'est une source inépuisable d'erreurs et de perte de temps. L'avantage avec SDLEP, c'est que si ça marche une fois ça marchera ensuite toujours, ce qui n'est pas le cas avec un lecteur analogique.
C'est une source inépuisable d'erreurs et de perte de temps. L'avantage avec SDLEP, c'est que si ça marche une fois ça marchera ensuite toujours, ce qui n'est pas le cas avec un lecteur analogique.
Daniel
L'obstacle augmente mon ardeur.
L'obstacle augmente mon ardeur.
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Concernant le MSX, les fichiers .wav générés par CAS Tools ou MSX Taper sont très aléatoires dans leur fonctionnement.
Ces dernières années, j'ai converti plusieurs dizaines de fichiers pour n'en garder qu'une petite vingtaine.
Il faudrait essayer avec le nouvel outil de Louthrax qui semble donner de bons résultats (je n'ai pas testé) d'après les retours. Cet utilitaire s'appelle sofacas, à télécharger sur son site http://lhalter.free.fr/mgr/sofacas.html
Ces dernières années, j'ai converti plusieurs dizaines de fichiers pour n'en garder qu'une petite vingtaine.
Il faudrait essayer avec le nouvel outil de Louthrax qui semble donner de bons résultats (je n'ai pas testé) d'après les retours. Cet utilitaire s'appelle sofacas, à télécharger sur son site http://lhalter.free.fr/mgr/sofacas.html
MSX - MSX2 - MSX2+ - MSXtR - VG5000
Trouvez l'intrus
Trouvez l'intrus
- Carl
- Modérateur
- Messages : 13253
- Inscription : 08 avr. 2007 13:21
- Localisation : http://www.doledujura.fr
- Contact :
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Merci riquet, je vais faire des tests...
Carl
Carl
- gleike
- Messages : 1341
- Inscription : 16 oct. 2014 11:12
- Localisation : Ludres (54710) Meurthe & Moselle
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Dans le but d'optimiser l'affichage LCD et l'utilisation du module SDLEP- READER
que je suis en train de mettre au point,
y-a-t-il un moyen dans le croquis Arduino de calculer le temps (minutes, secondes) de chargement
d'un programme en fonction de sa taille
avec la commande "AudioFileInfo.Size" ou autre ?
j'aimerais pouvoir l'afficher, ça aide a patienter.
Merci.
que je suis en train de mettre au point,
y-a-t-il un moyen dans le croquis Arduino de calculer le temps (minutes, secondes) de chargement
d'un programme en fonction de sa taille
avec la commande "AudioFileInfo.Size" ou autre ?
j'aimerais pouvoir l'afficher, ça aide a patienter.
Merci.
Dernière modification par gleike le 01 avr. 2017 18:19, modifié 1 fois.
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Il est possible de calculer la durée du chargement, mais ce n'est pas simple. La durée n'est pas fonction de la taille du fichier.
Le fichier .lep contient une succession de périodes. Voir ici le format : http://dcmoto.free.fr/bricolage/sdlep-reader/index.html
Pour calculer la durée, il faut lire chaque octet du fichier, en déduire la période correspondante et additionner toutes les périodes.
La période se calcule ainsi :
- Lire un octet (8 bits signés). S'il est nul prendre 127, sinon prendre la valeur absolue.
- Multiplier par l'unité de période (50 microsecondes).
Le fichier .lep contient une succession de périodes. Voir ici le format : http://dcmoto.free.fr/bricolage/sdlep-reader/index.html
Pour calculer la durée, il faut lire chaque octet du fichier, en déduire la période correspondante et additionner toutes les périodes.
La période se calcule ainsi :
- Lire un octet (8 bits signés). S'il est nul prendre 127, sinon prendre la valeur absolue.
- Multiplier par l'unité de période (50 microsecondes).
Daniel
L'obstacle augmente mon ardeur.
L'obstacle augmente mon ardeur.
- gleike
- Messages : 1341
- Inscription : 16 oct. 2014 11:12
- Localisation : Ludres (54710) Meurthe & Moselle
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Effectivement, ce n'est pas simple et ça nécessite de lire déjà une fois le fichier
avant de l'envoyer au to7, rien que pour calculer la durée.
Et je ne peux même pas afficher un compteur qui décrémenterais les octets envoyés de la taille total du fichier
car apparemment l’accès a l'affichage LCD n'est pas possible pendant la lecture avec les interruptions désactivés.
Tant pis, je vais me contenter de regarder clignoter la LED d'activité.
avant de l'envoyer au to7, rien que pour calculer la durée.
Et je ne peux même pas afficher un compteur qui décrémenterais les octets envoyés de la taille total du fichier
car apparemment l’accès a l'affichage LCD n'est pas possible pendant la lecture avec les interruptions désactivés.
Tant pis, je vais me contenter de regarder clignoter la LED d'activité.
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Le croquis Arduino utilisé par SDLEP-READER accède à la carte SD grâce à la bibliothèque SimpleSDAudio, mais n'utilise pas les fonctions de lecture et d'interprétation des fichiers .wav. Pour gagner de la place, j'ai fait une nouvelle version "expurgée", qui n'inclut pas la bibliothèque complète. Elle recopie seulement les fonctions utiles, et devient indépendante.
On passe ainsi de 5968 à 4178 octets de programme, et de 651 à 598 octets de variables globales. Dans la pratique ça ne change strictement rien au programme lui-même, par contre ça laisse un peu plus de place aux bidouilleurs qui voudront ajouter d'autres fonctions.
On passe ainsi de 5968 à 4178 octets de programme, et de 651 à 598 octets de variables globales. Dans la pratique ça ne change strictement rien au programme lui-même, par contre ça laisse un peu plus de place aux bidouilleurs qui voudront ajouter d'autres fonctions.
Code : Tout sélectionner
/**************************************************\
* S D - L E P *
* (c) 2017 - Daniel Coulom *
* http://dcmoto.free.fr/ *
* http://forum.system-cfg.com/ *
*--------------------------------------------------*
* Ce code est distribue gratuitement dans l'espoir *
* qu'il sera utile, mais sans aucune garantie et *
* sans engager la responsabilité de l'auteur. *
* Vous pouvez l' utiliser, le modifier et le *
* diffuser librement, en conservant cette licence *
* et les références de l'auteur dans toutes les *
* copies. L'exploitation commerciale est interdite.*
\**************************************************/
/***************************************************
* Version 2017.03.13 *
****************************************************
Historique
2017.03.13 integration des acces a la carte SD
2017.01.17 bit data a 1 pendant l'arret moteur
2016.12.30 unite du delai definie en parametre
2016.12.29 noms de fichiers .lep sur 7 caracteres
2016.12.19 quelques optimisations mineures
2016.12.18 clignotement LED si fichier non trouve
2016.12.18 nom de fichier choisi par switches
2016.12.17 choix de broches different pour les I/O
2016.12.17 delai en dixiemes de ms dans sd.lep
2016.12.16 ajout LED d'activite
2016.12.16 reste de count/127 ecrit avant les zeros
2016.12.14 premiere version du programme
Emulation d'un lecteur de cassette Thomson TO ou MO
Lecture des donnees sur carte SD dans un fichier au
format .lep (image de cassette Thomson).
Connexions vers module Catalex pour carte micro SD
GND --> GND
D13 --> SCK
D12 --> MISO
D11 --> MOSI
VCC --> VCC (5V)
D10 --> CS
Connexions vers DIN magnetophone
GND --> DIN 2
D0 --> DIN 1 (MOTOR)
D1 --> DIN 4 (READ DATA)
Connexion vers DIN crayon optique
VCC --> DIN 5 (+5V)
Connexion LED d'activite
D2 --> LED d'activite + resistance 1.5K
Connexion des interrupteurs de selection du fichier
D3 --> interrupteur 1
D4 --> interrupteur 2
D5 --> interrupteur 3
D6 --> interrupteur 4
D7 --> interrupteur 5
D8 --> interrupteur 6
D9 --> interrupteur 7
*****************************************************************
SD card management is adapted from SimpleSDAudio library.
Visit SimpleSDAudio website for more information:
http://www.hackerspace-ffm.de/wiki/index.php?title=SimpleSDAudio
*****************************************************************
*/
// SD card constants
#define SD_CARD_TYPE_SD1 1 /** Standard capacity V1 SD card */
#define SD_CARD_TYPE_SD2 2 /** Standard capacity V2 SD card */
#define SD_CARD_TYPE_SDHC 3 /** High Capacity SD card */
#define SD_PARTTYPE_UNKNOWN 0
#define SD_PARTTYPE_SUPERFLOPPY 1
#define SD_PARTTYPE_FAT16 2
#define SD_PARTTYPE_FAT32 3
#define SD_INIT_TIMEOUT 2000
#define SD_READ_TIMEOUT 300
#define SD_COMMAND_TIMEOUT 300
#define SD_READY_STATE 0x00 /** status for card in the ready state */
#define SD_IDLE_STATE 0x01 /** status for card in the idle state */
#define SD_ILLEGAL_COMMAND 0x04 /** status bit for illegal command */
#define SD_DATA_START_BLOCK 0xFE /** start data token for read or write single block*/
// SD card commands
#define SD_CMD0 0x00 /** GO_IDLE_STATE - init card in spi mode if CS low */
#define SD_CMD8 0x08 /** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
#define SD_CMD9 0x09 /** SEND_CSD - read the Card Specific Data (CSD register), response R1 */
#define SD_CMD10 0x0A /** SEND_CID - read the card identification information (CID register), response R1 */
#define SD_CMD12 0x0C /** STOP_TRANSMISSION - end multiple block read sequence, response R1b */
#define SD_CMD13 0x0D /** SEND_STATUS - read the card status register, response R2 */
#define SD_CMD16 0x10 /** SET_BLOCKLEN arg0[31:0]: block length, response R1 */
#define SD_CMD17 0x11 /** READ_SINGLE_BLOCK - read a single data block from the card, response R1 */
#define SD_CMD18 0x12 /** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card, response R1 */
#define SD_CMD55 0x37 /** APP_CMD - escape for application specific command */
#define SD_CMD58 0x3A /** READ_OCR - read the OCR register of a card */
#define SD_CMD59 0x3B /** CRC_ON_OFF - Turns CRC option on or off, response R1 */
#define SD_ACMD41 0x29 /** SD_SEND_OP_COMD - Sends host capacity support information and activates the card's initialization process */
// SD card error codes
#define SD_ERROR_CMD0 0x01 /** timeout error for command CMD0 (initialize card in SPI mode), signal problem */
#define SD_ERROR_CMD8 0x02 /** CMD8 was not accepted - not a valid SD card */
#define SD_ERROR_ACMD41 0x03 /** ACMD41 initialization process timeout */
#define SD_ERROR_CMD58 0x04 /** card returned an error response for CMD58 (read OCR) */
#define SD_ERROR_CMD16 0x05 /** card returned an error response for CMD16 (set block len) */
#define SD_ERROR_VOLTMATCH 0x06 /** card operation voltage range doesn't match (2.7V - 3.6V) */
#define SD_ERROR_READ_TIMEOUT 0x07 /** timeout while waiting for start of read data */
#define SD_ERROR_READ 0x08 /** card returned error token when tried to read data */
#define SD_ERROR_CMD17 0x09 /** card returned an error response for CMD17 (read single block) */
#define SD_ERROR_CMD9 0x0e /** card returned an error response for CMD9 (read CSD) */
#define SD_ERROR_CMD10 0x0f /** card returned an error response for CMD10 (read CID) */
#define SD_ERROR_CMD18 0x10 /** card returned an error response for CMD18 (read multi block) */
#define SD_ERROR_INVAL_SECT0 0x30 /** No valid MBR/FAT-BS signature found in sector 0 */
#define SD_ERROR_INVAL_BS 0x31 /** Malformed FAT boot sector */
#define SD_ERROR_FAT12 0x32 /** FAT12 is not supported */
#define SD_ERROR_FAT_NOT_INIT 0x33 /** FAT not initialized properly */
#define SD_ERROR_DIR_EOC 0x34 /** End of cluster reached (not a real error, just information) */
#define SD_ERROR_FILE_NOT_FOUND 0x35 /** File not found after reaching end of directory */
#define SD_ERROR_FRAGMET_FOUND 0x36 /** Fragmentation found */
#define SD_ERROR_FAT_ENTRY 0x37 /** Error in FAT entry */
#define SD_ERROR_EOF 0x38 /** End of file reached */
#define SD_ERROR_WORKBUF 0x39 /** WorkBuf not set */
// SD card variables
typedef struct {
uint8_t Attributes;
uint32_t Size; // in bytes
uint32_t FirstCluster; // First cluster
uint32_t ActSector; // 0 to (SD_FAT.SecPerClus - 1)
uint32_t ActBytePos; // 0 to Size
} SD_File_t;
SD_File_t AudioFileInfo;
typedef struct {
uint8_t PartType; // Use this to test whether it is FAT16 or FAT32 or not initialized
// Stuff from FAT boot sector
uint8_t SecPerClus;
uint16_t RsvdSecCnt;
uint8_t NumFATs;
uint16_t RootEntryCount;
uint32_t TotalSec;
uint32_t SecPerFAT;
uint32_t RootClus;
// For cluster calculations
uint8_t ClusterSizeShift;
uint32_t ClusterCount;
// Start addresses (all in blocks / sector addresses)
uint32_t BootSectorStart; // Address of boot sector from FAT
uint32_t FatStart; // First file allocation table starts here
uint32_t RootDirStart; // Root directory starts here
uint32_t DataStart; // Cluster 0 starts here
uint32_t ClusterEndMarker; // if Cluster >= this then end of file reached.
} SD_FAT_t;
SD_FAT_t SD_FAT;
uint8_t SD_type; // type de la carte SD
uint8_t SD_CSPin; // numero de la broche CS de la carte SD
uint8_t string[512]; // SD workbuf must hold at least 512 bytes
uint8_t *SD_workBuf; // pointeur vers buffer de travail
#define UNITE 50 //unite du delai en microsecondes
/**************************************************************************\
* Lecture du fichier .lep
\**************************************************************************/
void setup()
{
int i; // compteur de boucle
int delai; // delai en microsecondes
bool niveau; // niveau du signal en sortie
bool activite; // niveau diode d'activite
char octet; // zone de stockage d'un octet
uint32_t count = 0; // compteur d'octets
char filename[13]; // nom du fichier .lep
//Initialisations
pinMode(0, INPUT_PULLUP); // configurer pin0(RX) en entree (commande moteur)
pinMode(1, OUTPUT); // configurer pin1(TX) en sortie (donnees lues)
pinMode(2, OUTPUT); // configurer pin2 en sortie (led activite)
pinMode(3, INPUT_PULLUP); // interrupteur 1
pinMode(4, INPUT_PULLUP); // interrupteur 2
pinMode(5, INPUT_PULLUP); // interrupteur 3
pinMode(6, INPUT_PULLUP); // interrupteur 4
pinMode(7, INPUT_PULLUP); // interrupteur 5
pinMode(8, INPUT_PULLUP); // interrupteur 6
pinMode(9, INPUT_PULLUP); // interrupteur 7
SD_CSPin = 10; // definir CS de la carte SD en D10
SD_Init_FileSystem(string); // initialiser la carte SD
SD_SpiSetHighSpeed(); // frequence d'horloge maxi
//Determination du nom du fichier (extension .lep)
//en fonction de la position des 7 interrupteurs (128 possibilites)
//Le nom du fichier est compose de sept chiffres 0 ou 1
//decrivant la position des interrupteurs 1 à 7
//Exemple : interrupteurs 2, 4, 6 sur ON --> fichier 0101010.lep
//Exemple : interrupteurs 5 sur ON --> fichier 0000100.lep
//Exemple : interrupteurs 1,2,3,5,7 sur ON --> fichier 1110101.lep
strcpy(filename, "0000000.lep");
if(digitalRead(3) == LOW) filename[0] = '1';
if(digitalRead(4) == LOW) filename[1] = '1';
if(digitalRead(5) == LOW) filename[2] = '1';
if(digitalRead(6) == LOW) filename[3] = '1';
if(digitalRead(7) == LOW) filename[4] = '1';
if(digitalRead(8) == LOW) filename[5] = '1';
if(digitalRead(9) == LOW) filename[6] = '1';
// Search for file SD_FILE in Rootdir (=cluster 0),
// search shortname files only (0x00,0x18)
i = SD_SearchFile((uint8_t *)filename, 0UL, 0x00, 0x18, &AudioFileInfo);
//Si le fichier est trouve alors i est nul et on passe le while sans rien faire.
//Si le fichier n'est pas trouve alors i n'est pas nul et on boucle indefiniment.
//Remarque : La fonction delai necessite d'avoir les interruptions actives.
// On peut les desactiver apres, mais pas avant.
while(i) //clignotement rapide de la diode d'activite
{ //pour signaler un fichier non trouve
digitalWrite(2, HIGH); // allumer led activite
delay(5); // temporisation
digitalWrite(2, LOW); // eteindre led activite
delay(50); // temporisation
}
// send CMD18 (multiblock read)
noInterrupts(); // desactiver les interruptions
uint32_t offset = AudioFileInfo.ActSector; // offset = secteur
if (SD_type != SD_CARD_TYPE_SDHC) // si carte non SDHC
offset <<= 9; // offset = octet
SD_CardCommand(18, offset); // lance CMD18
niveau = HIGH; // signal a 1 pour detection lep
digitalWrite(1, niveau); // initialisation sortie
activite = LOW; // signal a 0 pour led d'activite
digitalWrite(2, activite); // eteindre led activite
while(count < AudioFileInfo.Size) // tant qu'il reste des octets
{
// attente octet 0xfe de debut de bloc
while(SD_SpiRecvByte() != 0xfe);
//traitement d'un bloc de 512 octets lus sur la carte SD
for(i = 0; i < 512; i++)
{
if(digitalRead(0) == HIGH) // si le moteur est arrete,
{ // pour que le LEP soit detecte,
digitalWrite(1, HIGH); // mettre le signal en sortie a 1
digitalWrite(2, LOW); // eteindre la led d'activite
while(digitalRead(0) == HIGH); // attendre le MOTOR ON
}
count++; // nombre d'octets lus
octet = SD_SpiRecvByte(); // lecture d'un octet
delai = abs(octet); // initialisation delai
if(octet == 0) delai = 127; // absence de signal (127 unites)
delai *= UNITE; // conversion en microsecondes
if(octet > 0) niveau = HIGH; // creneau positif
if(octet < 0) niveau = LOW; // creneau negatif
digitalWrite(1, niveau); // signal en sortie
//if(i == 511) delai -= 49; // compensation temps chgt bloc
delayMicroseconds(delai); // temporisation
}
//lecture des deux octets de CRC
SD_SpiRecvByte(); // lecture octet CRC1
SD_SpiRecvByte(); // lecture octet CRC2
//clignotement diode d'activite
activite = (activite == LOW) ? HIGH : LOW;
digitalWrite(2, activite);
}
digitalWrite(2, 0); // eteindre led activite
interrupts(); //activer les interruptions
}
/**************************************************************************\
* Flash toutes les deux secondes apres la fin de fichier
\**************************************************************************/
void loop(void) {
//la lecture est arrivee en fin de fichier
//clignotement lent de la diode d'activite
digitalWrite(2, HIGH); // allumer led activite
delay(100); // temporisation
digitalWrite(2, LOW); // eteindre led activite
delay(1900); // temporisation
}
/**************************************************************************\
* Set CS High
* Sends also one dummy byte to ensure MISO goes high impedance
\**************************************************************************/
void SD_SetCSHigh()
{
digitalWrite(SD_CSPin, HIGH);
SD_SpiSendByte(0xff);
}
/**************************************************************************\
* Sends a raw byte to the SPI - \param[in] b The byte to sent.
\**************************************************************************/
void SD_SpiSendByte(uint8_t b)
{
SPDR = b;
while(!(SPSR & (1 << SPIF))); /* wait for byte to be shifted out */
SPSR &= ~(1 << SPIF);
}
/**************************************************************************\
* wait for card to go not busy
\**************************************************************************/
uint8_t SD_WaitNotBusy(uint16_t timeout)
{
uint16_t t0 = ((uint16_t)millis());
while (SD_SpiRecvByte() != 0xFF) {if ((((uint16_t)millis()) - t0) >= timeout) return 0;}
return 1;
}
/**************************************************************************\
* Send a command to the memory card which responses with a R1 response
* (and possibly others).
* \param[in] command The command to send.
* \param[in] arg The argument for command.
* \returns The command answer.
\**************************************************************************/
uint8_t SD_CardCommand(uint8_t cmd, uint32_t arg)
{
uint8_t response;
uint8_t crc = 0xFF;
// select card
digitalWrite(SD_CSPin, LOW);
// wait up to timeout if busy
SD_WaitNotBusy(SD_COMMAND_TIMEOUT);
// send command
SD_SpiSendByte(cmd | 0x40);
// send argument
SD_SpiSendByte((arg >> 24) & 0xff);
SD_SpiSendByte((arg >> 16) & 0xff);
SD_SpiSendByte((arg >> 8) & 0xff);
SD_SpiSendByte((arg >> 0) & 0xff);
// send CRC, only required for commands 0 and 8
if (cmd == SD_CMD0) crc = 0x95; // correct crc for CMD0 with arg 0
if (cmd == SD_CMD8) crc = 0x87; // correct crc for CMD8 with arg 0X1AA
SD_SpiSendByte(crc);
// skip stuff byte for stop read
if (cmd == SD_CMD12) SD_SpiRecvByte();
// wait for response
for(uint8_t i = 0; i < 100; ++i)
{
response = SD_SpiRecvByte();
if(response != 0xff)
break;
}
return response;
}
/**************************************************************************\
* Send an application specific command which responses with a R1 response
* (and possibly others).
* \param[in] command The command to send.
* \param[in] arg The argument for command.
* \returns The command answer.
\**************************************************************************/
uint8_t SD_CardACommand(uint8_t cmd, uint32_t arg)
{
SD_CardCommand(SD_CMD55, 0);
return SD_CardCommand(cmd, arg);
}
/**************************************************************************\
* Initialize the SD memory card.
* Power up the card, set SPI mode.
* Detects the card version (V1, V2, SDHC), sets sector length to 512.
* \return Zero if successfull, errorcode otherwise
\**************************************************************************/
uint8_t SD_Init()
{
uint8_t status;
// 16-bit init start time allows over a minute
uint16_t t0 = ((uint16_t)millis());
uint32_t arg;
SD_type = 0;
/* Setup ports */
pinMode(SD_CSPin, OUTPUT);
digitalWrite(SD_CSPin, HIGH);
pinMode(MISO, INPUT);
pinMode(SCK, OUTPUT);
pinMode(MOSI, OUTPUT);
pinMode(SS, OUTPUT);
digitalWrite(SCK, LOW);
digitalWrite(MOSI, LOW);
digitalWrite(SS, HIGH);
/*
* SPI configuration:
* - enable uC for SPI master
* - typical no interrupts are used for SPI
* - data order: MSB is transmitted first
* - clock polarity: CLK is low when idle
* - clock phase: 1-0 > Sample, 0-1 > Setup
* - clock frequency: less than 400kHz
* (will be switched to higher value after initialization)
*/
/* initialize SPI with lowest frequency; max. 400kHz during identification mode of card */
SPCR = (0 << SPIE) | /* SPI Interrupt Enable */
(1 << SPE) | /* SPI Enable */
(0 << DORD) | /* Data Order: MSB first */
(1 << MSTR) | /* Master mode */
(0 << CPOL) | /* Clock Polarity: SCK low when idle */
(0 << CPHA) | /* Clock Phase: sample on rising SCK edge */
(1 << SPR1) | /* Clock Frequency: f_OSC / 128 */
(1 << SPR0);
SPSR &= ~(1 << SPI2X); /* No doubled clock frequency */
// must supply min of 74 clock cycles with CS high.
SD_SetCSHigh();
for (uint8_t i = 0; i < 10; i++) SD_SpiSendByte(0xFF);
// command to go idle in SPI mode
while ((SD_CardCommand(SD_CMD0, 0)) != SD_IDLE_STATE) {
if ((((uint16_t)millis()) - t0) > SD_INIT_TIMEOUT) {
SD_SetCSHigh();
return(SD_ERROR_CMD0);
}
}
// check SD version ( 2.7V - 3.6V + test pattern )
if ((SD_CardCommand(SD_CMD8, 0x1AA) & SD_ILLEGAL_COMMAND)) {
SD_type = SD_CARD_TYPE_SD1;
// Not done here: Test if SD or MMC card here using CMD55 + CMD1
} else {
// only need last byte of r7 response
SD_SpiRecvByte();
SD_SpiRecvByte();
status = SD_SpiRecvByte();
if ((status & 0x01) == 0) {
// card operation voltage range doesn't match
SD_SetCSHigh();
return(SD_ERROR_VOLTMATCH);
}
if (SD_SpiRecvByte() != 0xAA) {
SD_SetCSHigh();
return(SD_ERROR_CMD8);
}
SD_type = SD_CARD_TYPE_SD2;
}
// Turn CRC option off
SD_CardCommand(SD_CMD59, 0);
// initialize card and send host supports SDHC if SD2
arg = (SD_type == SD_CARD_TYPE_SD2) ? 0X40000000 : 0;
while ((SD_CardACommand(SD_ACMD41, arg)) != SD_READY_STATE) {
// check for timeout
if ((((uint16_t)millis()) - t0) > SD_INIT_TIMEOUT) {
SD_SetCSHigh();
return(SD_ERROR_ACMD41);
}
}
// if SD2 read OCR register to check for SDHC card
if (SD_type == SD_CARD_TYPE_SD2) {
if (SD_CardCommand(SD_CMD58, 0)) {
SD_SetCSHigh();
return(SD_ERROR_CMD58);
}
// other implementation test only against 0x40 for SDHC detection...
if ((SD_SpiRecvByte() & 0xC0) == 0xC0) SD_type = SD_CARD_TYPE_SDHC;
// discard rest of ocr - contains allowed voltage range
SD_SpiRecvByte();
SD_SpiRecvByte();
SD_SpiRecvByte();
}
// set block size to 512 bytes
if(SD_CardCommand(SD_CMD16, 512))
{
SD_SetCSHigh();
return(SD_ERROR_CMD16);
}
SD_SetCSHigh();
SD_SpiSetHighSpeed();
return 0;
}
/**************************************************************************\
* Initialize the file system .
* Does the lower level initialization and * tries to find the boot sector
* of the first FAT16 or FAT32 partition and parse it.
* Workbuf must hold at least 512 bytes.
* Workbuf will be used later also for following functions:
* - SD_SearchFile
* - SD_Dir
* \return Zero if successful, error code otherwise
\**************************************************************************/
uint8_t SD_Init_FileSystem(uint8_t *pWorkBuf)
{
uint8_t retval;
uint8_t PartType;
uint16_t temp16;
uint32_t temp32;
SD_FAT.PartType = SD_PARTTYPE_UNKNOWN;
if(pWorkBuf == NULL) return(SD_ERROR_WORKBUF);
SD_workBuf = pWorkBuf;
// Try init SD-Card
retval = SD_Init();
if(retval) return(retval);
// ==== MBR (partition table) access here =====
// Read sector 0
retval = SD_ReadBlock(0, SD_workBuf);
if(retval) return(retval);
// Test for signature (valid not only for MBR, but FAT Boot Sector as well!)
if((SD_workBuf[0x1fe] != 0x55) || (SD_workBuf[0x1ff] != 0xaa)) return(SD_ERROR_INVAL_SECT0);
// Store most important MBR values for first partition
PartType = SD_workBuf[0x1be + 0x04];
SD_FAT.BootSectorStart = (uint32_t)SD_workBuf[0x1be + 0x08]
| ((uint32_t)SD_workBuf[0x1be + 0x09] << 8UL)
| ((uint32_t)SD_workBuf[0x1be + 0x0a] << 16UL)
| ((uint32_t)SD_workBuf[0x1be + 0x0b] << 24UL);
// Check MBR values for plausibility
if( ((SD_workBuf[0x1be] & 0x7f) == 0)
&& ((PartType == 0x04) || (PartType == 0x06) || (PartType == 0x0B)
|| (PartType == 0x0C) || (PartType == 0x0E)) )
{
// MBR seems to contain valid FAT16/FAT32 partition entry
SD_FAT.PartType = ((PartType == 0x0B) || (PartType == 0x0C)) ? SD_PARTTYPE_FAT32 : SD_PARTTYPE_FAT16;
}
else
{
// MBR seems to contain not an valid entry, so try for super-floppy now
SD_FAT.BootSectorStart = 0UL;
SD_FAT.PartType = SD_PARTTYPE_SUPERFLOPPY;
}
// ====== FAT access here ======
// Read Boot-Sector and test for signature
retval = SD_ReadBlock(SD_FAT.BootSectorStart, SD_workBuf);
if(retval) return(retval);
// Test for signature (valid not only for MBR, but FAT Boot Sector as well!)
if((SD_workBuf[0x1fe] != 0x55) || (SD_workBuf[0x1ff] != 0xaa)) return(SD_ERROR_INVAL_BS);
// Plausibility checks for FAT
if((SD_workBuf[0x0b] != 0x00) || (SD_workBuf[0x0c] != 0x02) || (SD_workBuf[0x15] != 0xf8)) return(SD_ERROR_INVAL_BS);
// Read fields that are same for FAT16 and FAT32
SD_FAT.SecPerClus = SD_workBuf[0x0d];
SD_FAT.RsvdSecCnt = (uint16_t)SD_workBuf[0x0e] | ((uint16_t)SD_workBuf[0x0f]<<8U);
if((SD_FAT.SecPerClus == 0) || (SD_FAT.RsvdSecCnt == 0)) return(SD_ERROR_INVAL_BS);
SD_FAT.NumFATs = SD_workBuf[0x10];
SD_FAT.RootEntryCount = (uint16_t)SD_workBuf[0x11] | ((uint16_t)SD_workBuf[0x12]<<8U);
temp16 = (uint16_t)SD_workBuf[0x13] | ((uint16_t)SD_workBuf[0x14]<<8U);
temp32 = (uint32_t)SD_workBuf[0x20] | ((uint32_t)SD_workBuf[0x21]<<8U) | ((uint32_t)SD_workBuf[0x22]<<16U) | ((uint32_t)SD_workBuf[0x23]<<24U);
SD_FAT.TotalSec = temp16 ? temp16 : temp32;
temp16 = (uint16_t)SD_workBuf[0x16] | ((uint16_t)SD_workBuf[0x17]<<8U);
temp32 = (uint32_t)SD_workBuf[0x24] | ((uint32_t)SD_workBuf[0x25]<<8U) | ((uint32_t)SD_workBuf[0x26]<<16U) | ((uint32_t)SD_workBuf[0x27]<<24U);
SD_FAT.SecPerFAT = temp16 ? temp16 : temp32;
// Calculate start sectors
SD_FAT.FatStart = SD_FAT.BootSectorStart + (uint32_t)SD_FAT.RsvdSecCnt;
SD_FAT.RootDirStart = SD_FAT.FatStart + SD_FAT.NumFATs * (uint32_t)SD_FAT.SecPerFAT;
// Data area starts at cluster #2
SD_FAT.DataStart = SD_FAT.RootDirStart+ ((32 * (uint32_t)SD_FAT.RootEntryCount + 511)/512) - (2 * SD_FAT.SecPerClus);
// determine shift that is same as multiply by SD_FAT.SecPerClus
SD_FAT.ClusterSizeShift = 0;
while (SD_FAT.SecPerClus != (1 << SD_FAT.ClusterSizeShift)) {
// error if not power of 2
if (SD_FAT.ClusterSizeShift++ > 7) return(SD_ERROR_INVAL_BS);
}
// Calculate number and shifting of clusters
// total data blocks
SD_FAT.ClusterCount = SD_FAT.TotalSec - (SD_FAT.DataStart - SD_FAT.BootSectorStart);
// divide by cluster size to get cluster count
SD_FAT.ClusterCount >>= SD_FAT.ClusterSizeShift;
// determine if FAT16 or FAT32 (only by cluster count as done by M$)
if (SD_FAT.ClusterCount < 4085) {
// this would be FAT12, which is not supported
SD_FAT.PartType = SD_PARTTYPE_UNKNOWN;
return(SD_ERROR_FAT12);
} else if (SD_FAT.ClusterCount < 65525) {
SD_FAT.PartType = SD_PARTTYPE_FAT16;
SD_FAT.ClusterEndMarker = 0xfff8UL;
} else {
temp32 = (uint32_t)SD_workBuf[0x2c] | ((uint32_t)SD_workBuf[0x2d]<<8U) | ((uint32_t)SD_workBuf[0x2e]<<16U) | ((uint32_t)SD_workBuf[0x2f]<<24U);
SD_FAT.RootDirStart = SD_Cluster2Sector(temp32);
SD_FAT.PartType = SD_PARTTYPE_FAT32;
SD_FAT.ClusterEndMarker = 0xffffff8UL;
}
return 0;
}
/**************************************************************************\
* Set SPI for full operation speed (up to 25 MHz).
* Will be called after first part of card
* initialization was successful.
\**************************************************************************/
void SD_SpiSetHighSpeed(void)
{
SPCR &= ~((1 << SPR1) | (1 << SPR0)); /* Clock Frequency: f_OSC / 4 */
SPSR |= (1 << SPI2X); /* Doubled Clock Frequency: f_OSC / 2 */
}
/**************************************************************************\
* Receives a raw byte from the SPI.
* \returns The byte which should be read.
\**************************************************************************/
uint8_t SD_SpiRecvByte()
{
SPDR = 0xff; /* send dummy data for receiving some */
while(!(SPSR & (1 << SPIF)));
SPSR &= ~(1 << SPIF);
return SPDR;
}
/**************************************************************************\
* SPI read data - only one call so force inline
* Receives nbytes in buf. Send 0xff all the time.
\**************************************************************************/
//inline __attribute__((always_inline))
void SD_SpiRecvBlock(uint8_t *buf, uint16_t nbyte)
{
if (nbyte-- == 0) return;
SPDR = 0xFF;
for (uint16_t i = 0; i < nbyte; i++) {
while (!(SPSR & (1 << SPIF)));
buf[i] = SPDR;
SPDR = 0xFF;
}
while (!(SPSR & (1 << SPIF)));
buf[nbyte] = SPDR;
}
/**************************************************************************\
* Read one block of data from card.
* \return Error code, 0 if ok.
\**************************************************************************/
uint8_t SD_ReadData(uint8_t *dst, uint16_t count)
{
// wait for start block token
uint8_t status;
uint16_t t0 = ((uint16_t)millis());
while ((status = SD_SpiRecvByte()) == 0xFF) {
if ((((uint16_t)millis()) - t0) > SD_READ_TIMEOUT) {
SD_SetCSHigh();
return(SD_ERROR_READ_TIMEOUT);
}
}
if (status != SD_DATA_START_BLOCK) {
SD_SetCSHigh();
return(SD_ERROR_READ);
}
// transfer data
SD_SpiRecvBlock(dst, count);
// discard CRC
SD_SpiRecvByte();
SD_SpiRecvByte();
SD_SetCSHigh();
return 0;
}
/**************************************************************************\
* Read a 512 byte block from an SD card.
* \param[in] blockNumber Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return 0 is returned for success, error code otherwise
\**************************************************************************/
uint8_t SD_ReadBlock(uint32_t blockNumber, uint8_t *dst)
{
// use address if not SDHC card
if (SD_type != SD_CARD_TYPE_SDHC) blockNumber <<= 9;
if (SD_CardCommand(SD_CMD17, blockNumber)) {SD_SetCSHigh(); return(SD_ERROR_CMD17);}
return SD_ReadData(dst, 512);
}
/**************************************************************************\
* Returns the first sector of a given cluster
\**************************************************************************/
uint32_t SD_Cluster2Sector(uint32_t cluster)
{
return((cluster << SD_FAT.ClusterSizeShift) + SD_FAT.DataStart);
}
/**************************************************************************\
* Search a file in the directory.
* Filename must be 8.3 format, terminated by \0 (can not access ".." now...)
* Works only over one cluster of directory information.
* If SD_ERROR_DIR_EOC is returned call function again with next cluster number.
* Set cluster to 0 to access root directory.
* Deleted files and long name entries are not shown generally.
* Only files are printed that has their attributes set/unset regarding maskSet/maskUnset.
* Examples for maskSet, maskUnset:
* Ouput everything: 0x00, 0x00
* Shortname files only: 0x00, 0x18
* Shortname files and dirs: 0x00, 0x08
* Shortname dirs: 0x10, 0x08
* Volume name: 0x08, 0x10
* Mask bits: B7 = 0, B6 = 0, B5 = archive, B4 = directory,
* B3 = volume name, B2 = system, B1 = hidden, B0 = read only
* If file is found, fileinfo gets filled with file attributes,
* file size in bytes and first cluster.
* return Zero if successfully, error code otherwise
\**************************************************************************/
uint8_t SD_SearchFile(uint8_t *filename, const uint32_t cluster, const uint8_t maskSet, const uint8_t maskUnset, SD_File_t *fileinfo)
{
uint16_t maxsect = SD_FAT.SecPerClus;
uint32_t startsect = SD_Cluster2Sector(cluster);
char fnentry[12];
if((SD_FAT.PartType != SD_PARTTYPE_FAT16) && (SD_FAT.PartType != SD_PARTTYPE_FAT32)) return(SD_ERROR_FAT_NOT_INIT);
if(cluster == 0)
{
startsect = SD_FAT.RootDirStart; // Set root dir sector
if(SD_FAT.PartType == SD_PARTTYPE_FAT16) maxsect = (uint16_t)((32 * (uint32_t)SD_FAT.RootEntryCount + 511)/512);
}
// convert filename to space-filled uppercase format
for(uint8_t i = 0; i < 11; i++) fnentry[i] = ' ';
for(uint8_t i = 0; i < 9; i++)
{
uint8_t c = *filename++;
if((c < 0x20) || (c == '.')) break;
if((c>='a') && (c<='z')) c -= 0x20; // to upper case
fnentry[i] = c;
}
for(uint8_t i = 8; i < 11; i++)
{
uint8_t c = *filename++;
if(c < 0x20) break;
if((c>='a') && (c<='z')) c -= 0x20; // to upper case
fnentry[i] = c;
}
fnentry[11] = 0;
//Serial.println(fnentry);
// go through sectors
for(uint16_t i = 0; i<maxsect; i++)
{
uint8_t retval = SD_ReadBlock(startsect + i, SD_workBuf);
if(retval) return(retval);
for(uint16_t j = 0; j<512; j+=32)
{
uint8_t attrib;
if(SD_workBuf[j] == 0) return(SD_ERROR_FILE_NOT_FOUND); // Last entry when first character of filename == 0
if(SD_workBuf[j] == 0xe5) continue; // Skip deleted files
if(SD_workBuf[j] == 0x05) SD_workBuf[j] = 0xE5;
attrib = SD_workBuf[j+0x0b];
// Test masks (skip long file name entries also)
if(((attrib & maskSet) == maskSet) && ((attrib & maskUnset) == 0) && (attrib != 0x0f))
{
uint16_t k;
// compare filename
for(k = 0; k < 11; k++) if(SD_workBuf[j+k] != fnentry[k]) break;
if(k >= 11)
{
// found it
fileinfo->Attributes = attrib;
fileinfo->Size = (uint32_t)SD_workBuf[j+0x1c] | (((uint32_t)SD_workBuf[j+0x1d])<<8)
| (((uint32_t)SD_workBuf[j+0x1e])<<16) | (((uint32_t)SD_workBuf[j+0x1f])<<24);
if(SD_FAT.PartType == SD_PARTTYPE_FAT16)
{fileinfo->FirstCluster = (uint32_t)SD_workBuf[j+0x1a] | (((uint32_t)SD_workBuf[j+0x1b])<<8);}
else
{fileinfo->FirstCluster = (uint32_t)SD_workBuf[j+0x1a] | (((uint32_t)SD_workBuf[j+0x1b])<<8)
| (((uint32_t)SD_workBuf[j+0x14])<<16) | (((uint32_t)SD_workBuf[j+0x15])<<24);}
// Initialize some things
fileinfo->ActSector = SD_Cluster2Sector(fileinfo->FirstCluster);
fileinfo->ActBytePos = 0;
return(0);
}
}
}
}
if(SD_FAT.PartType == SD_PARTTYPE_FAT16) return(SD_ERROR_FILE_NOT_FOUND);
return(SD_ERROR_DIR_EOC);
}
Daniel
L'obstacle augmente mon ardeur.
L'obstacle augmente mon ardeur.
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Bonjour à tous...
...et plus particulièrement à Daniel à qui s'adresseront mes questions.
J'ai fait il y a quelques jours la démonstration à un ami du contrôleur CS91-282, installé il y a quelques mois dans mon MO5.
Il a été enchanté de revoir certains jeux qui l'avaient marqué dans sa jeunesse.
Cependant, il a mis le doigt sur une "lacune" qui n'est pas propre au contrôleur mais qui l'a un peu déçu lors de la démonstration : il n'a pas pu revoir certains jeux qui n'existent qu'au format k7 comme par exemple "Pop Pop" qui l'avait marqué je ne sais pourquoi ?
Je me suis donc dis qu'un génial informaticien bricoleur avait certainement trouvé une solution à ce problème !
Après la recherche et la lecture (un peu rapide il est vrai) des 13 pages du forum dédiées au SDLEP-Reader, une question principale se pose à moi : les conversions successives des fichiers .k7 en .wav (avec DCMOK7) puis de .wav en .lep (avec DCLEP) fonctionnent t-elles à coup sûr ou existe t-il une autre méthode ?
Quoi qu'il en soit, je serait intéressé par l'achat des lots 1 et 2 s'ils sont disponibles ?
Merci d'avance.
Sam
...et plus particulièrement à Daniel à qui s'adresseront mes questions.
J'ai fait il y a quelques jours la démonstration à un ami du contrôleur CS91-282, installé il y a quelques mois dans mon MO5.
Il a été enchanté de revoir certains jeux qui l'avaient marqué dans sa jeunesse.
Cependant, il a mis le doigt sur une "lacune" qui n'est pas propre au contrôleur mais qui l'a un peu déçu lors de la démonstration : il n'a pas pu revoir certains jeux qui n'existent qu'au format k7 comme par exemple "Pop Pop" qui l'avait marqué je ne sais pourquoi ?
Je me suis donc dis qu'un génial informaticien bricoleur avait certainement trouvé une solution à ce problème !
Après la recherche et la lecture (un peu rapide il est vrai) des 13 pages du forum dédiées au SDLEP-Reader, une question principale se pose à moi : les conversions successives des fichiers .k7 en .wav (avec DCMOK7) puis de .wav en .lep (avec DCLEP) fonctionnent t-elles à coup sûr ou existe t-il une autre méthode ?
Quoi qu'il en soit, je serait intéressé par l'achat des lots 1 et 2 s'ils sont disponibles ?
Merci d'avance.
Sam
-
- Messages : 7923
- Inscription : 18 sept. 2010 12:08
- Localisation : Brest et parfois les Flandres
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Si c'est pour mo5 il y a une solution sauvant l 'état de l’émulateur dans un fichier sd utilisable sur mo5 je crois.
Samuel.
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
A500 Vampire V2+ ^8^, A1200 (030@50mhz/fpu/64mb/cf 8go),
A500 GVP530(MMU/FPU) h.s., R-Pi, TO9, TO8D, TO8.Démos
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Les fichiers .lep pour n'importe quel ordinateur Thomson fonctionnent à coup sûr quand je les crée moi-même. Jusqu'à maintenant la réussite est de 100%, aussi bien pour les jeux commerciaux protégés que pour les programmes Basic. La seule différence avec un magnétophone est la suppression totale et définitive des erreurs de lecture.
Si le but est simplement d'utiliser le jeu sur MO5, la solution donnée par __sam__ est certainement plus simple, et surtout le chargement est beaucoup plus rapide : une dizaine de secondes avec le fichier .sd, contre une dizaine de minutes pour une cassette ou un fichier .lep. Voir ici : viewtopic.php?f=24&t=5759&start=78
Pour que la sauvegarde de l'état de l'émulateur fonctionne bien avec le "vrai" MO5, il faut la faire à un moment judicieux. Normalement juste après la fin du chargement et juste avant le début du jeu. En cas de difficulté n'hésitez pas à demander de l'aide dans le fil de discussion DCMOTO nouveau.
Si le but est simplement d'utiliser le jeu sur MO5, la solution donnée par __sam__ est certainement plus simple, et surtout le chargement est beaucoup plus rapide : une dizaine de secondes avec le fichier .sd, contre une dizaine de minutes pour une cassette ou un fichier .lep. Voir ici : viewtopic.php?f=24&t=5759&start=78
Pour que la sauvegarde de l'état de l'émulateur fonctionne bien avec le "vrai" MO5, il faut la faire à un moment judicieux. Normalement juste après la fin du chargement et juste avant le début du jeu. En cas de difficulté n'hésitez pas à demander de l'aide dans le fil de discussion DCMOTO nouveau.
Daniel
L'obstacle augmente mon ardeur.
L'obstacle augmente mon ardeur.
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Merci Sam et Daniel.
Effectivement, c'est beaucoup plus simple (et économique)
Je vais tester ça dès que possible et je vous tiens informé en cas de difficulté.
Effectivement, c'est beaucoup plus simple (et économique)
Je vais tester ça dès que possible et je vous tiens informé en cas de difficulté.
- Carl
- Modérateur
- Messages : 13253
- Inscription : 08 avr. 2007 13:21
- Localisation : http://www.doledujura.fr
- Contact :
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
Daniel, tu trouveras le wav généré avec le logiciel sofacas et le wav sortie SDLEP, le 1er se charge en lecteur wav, le second se plante SDLEP...
Si tu as une idée...
Enregistrement (9).7z
https://download.system-cfg.com/f.php?h=3j3tJsEH&d=1
Carl
Si tu as une idée...
Enregistrement (9).7z
https://download.system-cfg.com/f.php?h=3j3tJsEH&d=1
Carl
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
J'ai fait l'essai suivant :
1) Génération du fichier .lep à partir de test sofacas.wav
2) Enregistrement de la sortie de SDLEP-READER avec une carte son de PC
Résultat (disponible 1 mois) : http://dl.free.fr/fhSroFssB
Le fichier .wav obtenu est pratiquement identique au fichier original. Il n'y a jamais plus de 50 µs d'écart dans les périodes des signaux.
Le problème n'est donc pas du à la logique de codage et de décodage du signal. Il peut avoir différentes causes matérielles : mauvais contacts dans le câble, mauvaise adaptation d'impédance entre la sortie de l'Arduino et l'entrée de l'ordinateur, problème d'alimentation, parasites, etc. Je n'ai pas malheureusement pas de MSX pour faire l'essai moi-même.
Autre point : attention aux formats de compression audio avec pertes. Ils ne sont pas adaptés à la compression de données, comme celles qui se trouvent sur les cassettes de programmes. A la limite ces compressions peuvent être acceptables pour des fichiers audio (bien que les véritables audiophiles ne les supportent pas). Pour des données numériques c'est un source d'erreurs de décodage.
1) Génération du fichier .lep à partir de test sofacas.wav
2) Enregistrement de la sortie de SDLEP-READER avec une carte son de PC
Résultat (disponible 1 mois) : http://dl.free.fr/fhSroFssB
Le fichier .wav obtenu est pratiquement identique au fichier original. Il n'y a jamais plus de 50 µs d'écart dans les périodes des signaux.
Le problème n'est donc pas du à la logique de codage et de décodage du signal. Il peut avoir différentes causes matérielles : mauvais contacts dans le câble, mauvaise adaptation d'impédance entre la sortie de l'Arduino et l'entrée de l'ordinateur, problème d'alimentation, parasites, etc. Je n'ai pas malheureusement pas de MSX pour faire l'essai moi-même.
Autre point : attention aux formats de compression audio avec pertes. Ils ne sont pas adaptés à la compression de données, comme celles qui se trouvent sur les cassettes de programmes. A la limite ces compressions peuvent être acceptables pour des fichiers audio (bien que les véritables audiophiles ne les supportent pas). Pour des données numériques c'est un source d'erreurs de décodage.
Daniel
L'obstacle augmente mon ardeur.
L'obstacle augmente mon ardeur.
- Carl
- Modérateur
- Messages : 13253
- Inscription : 08 avr. 2007 13:21
- Localisation : http://www.doledujura.fr
- Contact :
Re: SDLEP-READER remplace tous les magnétophones d'ordinateurs.
En effet le Wav issu du SDLEP passe très bien sur MSX...
Je viens de mettre une légère amplification du signal de sortie jack audio du SDLEP et bingo, les fichiers LEP se sont chargés à 100%
conclusion :
VG5000___________pas besoin d'ampli
Alice 4/32/90______pas besoin d'ampli
EXL 100___________pas besoin d'ampli
MSX______________besoin ampli
Carl
Je viens de mettre une légère amplification du signal de sortie jack audio du SDLEP et bingo, les fichiers LEP se sont chargés à 100%
conclusion :
VG5000___________pas besoin d'ampli
Alice 4/32/90______pas besoin d'ampli
EXL 100___________pas besoin d'ampli
MSX______________besoin ampli
Carl