Not sure what you mean by "hides flash pages handling" but I adapted portions of the SerialFlashChip.h and .cpp files to accomplish my end. I use these portions to read/write to individual byte addresses :
void SerialFlashChip::read(uint32_t addr, void *buf, uint32_t len)
{
uint8_t *p = (uint8_t *)buf;
uint8_t b, f, status, cmd;
memset(p, 0, len);
f = flags;
SPIPORT.beginTransaction(SPICONFIG);
b = busy;
if (b) {
// read status register ... chip may no longer be busy
CSASSERT();
if (flags & FLAG_STATUS_CMD70) {
SPIPORT.transfer(0x70);
status = SPIPORT.transfer(0);
if ((status & 0x80)) b = 0;
} else {
SPIPORT.transfer(0x05);
status = SPIPORT.transfer(0);
if (!(status & 1)) b = 0;
}
CSRELEASE();
if (b == 0) {
// chip is no longer busy 
busy = 0;
} else if (b < 3) {
// TODO: this may not work on Spansion chips
// which apparently have 2 different suspend
// commands, for program vs erase
CSASSERT();
SPIPORT.transfer(0x06); // write enable (Micron req'd)
CSRELEASE();
delayMicroseconds(1);
cmd = 0x75; //Suspend program/erase for almost all chips
// but Spansion just has to be different for program suspend!
if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x85;
CSASSERT();
SPIPORT.transfer(cmd); // Suspend command
CSRELEASE();
if (f & FLAG_STATUS_CMD70) {
// Micron chips don't actually suspend until flags read
CSASSERT();
SPIPORT.transfer(0x70);
do {
status = SPIPORT.transfer(0);
} while (!(status & 0x80));
CSRELEASE();
} else {
CSASSERT();
SPIPORT.transfer(0x05);
do {
status = SPIPORT.transfer(0);
} while ((status & 0x01));
CSRELEASE();
}
} else {
// chip is busy with an operation that can not suspend
SPIPORT.endTransaction(); // is this a good idea?
wait(); // should we wait without ending
b = 0; // the transaction??
SPIPORT.beginTransaction(SPICONFIG);
}
}
do {
uint32_t rdlen = len;
if (f & FLAG_MULTI_DIE) {
if ((addr & 0xFE000000) != ((addr + len - 1) & 0xFE000000)) {
rdlen = 0x2000000 - (addr & 0x1FFFFFF);
}
}
CSASSERT();
// TODO: FIFO optimize....
if (f & FLAG_32BIT_ADDR) {
SPIPORT.transfer(0x03);
SPIPORT.transfer16(addr >> 16);
SPIPORT.transfer16(addr);
} else {
SPIPORT.transfer16(0x0300 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
}
SPIPORT.transfer(p, rdlen);
CSRELEASE();
p += rdlen;
addr += rdlen;
len -= rdlen;
} while (len > 0);
if (b) {
CSASSERT();
SPIPORT.transfer(0x06); // write enable (Micron req'd)
CSRELEASE();
delayMicroseconds(1);
cmd = 0x7A;
if ((f & FLAG_DIFF_SUSPEND) && (b == 1)) cmd = 0x8A;
CSASSERT();
SPIPORT.transfer(cmd); // Resume program/erase
CSRELEASE();
}
SPIPORT.endTransaction();
}
void SerialFlashChip::write(uint32_t addr, const void *buf, uint32_t len)
{
const uint8_t *p = (const uint8_t *)buf;
uint32_t max, pagelen;
//Serial.printf("WR: addr %08X, len %d\n", addr, len);
do {
if (busy) wait();
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
// write enable command
SPIPORT.transfer(0x06);
CSRELEASE();
max = 256 - (addr & 0xFF);
pagelen = (len <= max) ? len : max;
//Serial.printf("WR: addr %08X, pagelen %d\n", addr, pagelen);
delayMicroseconds(1); // TODO: reduce this, but prefer safety first
CSASSERT();
if (flags & FLAG_32BIT_ADDR) {
SPIPORT.transfer(0x02); // program page command
SPIPORT.transfer16(addr >> 16);
SPIPORT.transfer16(addr);
} else {
SPIPORT.transfer16(0x0200 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
}
addr += pagelen;
len -= pagelen;
do {
SPIPORT.transfer(*p++);
} while (--pagelen > 0);
CSRELEASE();
busy = 4;
SPIPORT.endTransaction();
} while (len > 0);
}
I then added these lines to SerialFlachChip.cpp :
void SerialFlashChip::eraseBlock32(uint32_t addr)
{
uint8_t f = flags;
if (busy) wait();
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
SPIPORT.transfer(0x06); // write enable command
CSRELEASE();
delayMicroseconds(1);
CSASSERT();
if (f & FLAG_32BIT_ADDR) {
SPIPORT.transfer(0x52);
SPIPORT.transfer16(addr >> 16);
SPIPORT.transfer16(addr);
} else {
SPIPORT.transfer16(0xD800 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
}
CSRELEASE();
SPIPORT.endTransaction();
busy = 2;
}
void SerialFlashChip::eraseSector(uint32_t addr)
{
uint8_t f = flags;
if (busy) wait();
SPIPORT.beginTransaction(SPICONFIG);
CSASSERT();
SPIPORT.transfer(0x06); // write enable command
CSRELEASE();
delayMicroseconds(1);
CSASSERT();
if (f & FLAG_32BIT_ADDR) {
SPIPORT.transfer(0x20);
SPIPORT.transfer16(addr >> 16);
SPIPORT.transfer16(addr);
} else {
SPIPORT.transfer16(0xD800 | ((addr >> 16) & 255));
SPIPORT.transfer16(addr);
}
CSRELEASE();
SPIPORT.endTransaction();
busy = 2;
}
...and finally added these lines to SerialFlashChip.h :
static void eraseBlock32(uint32_t addr);
static void eraseSector(uint32_t addr);
Here is the 1st line of my sketch:
#include <SerialFlash.h>